mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 03:19:46 +00:00
add more metadata to IPFSUploader
This commit is contained in:
parent
6171a321e2
commit
b0a2422437
3 changed files with 67 additions and 2 deletions
|
|
@ -41,6 +41,7 @@
|
||||||
"@gfx/canvas-wasm": "jsr:@gfx/canvas-wasm@^0.4.2",
|
"@gfx/canvas-wasm": "jsr:@gfx/canvas-wasm@^0.4.2",
|
||||||
"@hono/hono": "jsr:@hono/hono@^4.4.6",
|
"@hono/hono": "jsr:@hono/hono@^4.4.6",
|
||||||
"@isaacs/ttlcache": "npm:@isaacs/ttlcache@^1.4.1",
|
"@isaacs/ttlcache": "npm:@isaacs/ttlcache@^1.4.1",
|
||||||
|
"@jcayzac/image-information": "npm:@jcayzac/image-information@1.1.1",
|
||||||
"@lambdalisue/async": "jsr:@lambdalisue/async@^2.1.1",
|
"@lambdalisue/async": "jsr:@lambdalisue/async@^2.1.1",
|
||||||
"@negrel/webpush": "jsr:@negrel/webpush@^0.3.0",
|
"@negrel/webpush": "jsr:@negrel/webpush@^0.3.0",
|
||||||
"@noble/secp256k1": "npm:@noble/secp256k1@^2.0.0",
|
"@noble/secp256k1": "npm:@noble/secp256k1@^2.0.0",
|
||||||
|
|
@ -59,6 +60,7 @@
|
||||||
"@std/json": "jsr:@std/json@^0.223.0",
|
"@std/json": "jsr:@std/json@^0.223.0",
|
||||||
"@std/media-types": "jsr:@std/media-types@^0.224.1",
|
"@std/media-types": "jsr:@std/media-types@^0.224.1",
|
||||||
"@std/streams": "jsr:@std/streams@^0.223.0",
|
"@std/streams": "jsr:@std/streams@^0.223.0",
|
||||||
|
"blurhash": "npm:blurhash@2.0.5",
|
||||||
"comlink": "npm:comlink@^4.4.1",
|
"comlink": "npm:comlink@^4.4.1",
|
||||||
"comlink-async-generator": "npm:comlink-async-generator@^0.0.1",
|
"comlink-async-generator": "npm:comlink-async-generator@^0.0.1",
|
||||||
"commander": "npm:commander@12.1.0",
|
"commander": "npm:commander@12.1.0",
|
||||||
|
|
|
||||||
28
deno.lock
generated
28
deno.lock
generated
|
|
@ -80,12 +80,14 @@
|
||||||
"jsr:@std/streams@0.223": "0.223.0",
|
"jsr:@std/streams@0.223": "0.223.0",
|
||||||
"npm:@electric-sql/pglite@~0.2.8": "0.2.8",
|
"npm:@electric-sql/pglite@~0.2.8": "0.2.8",
|
||||||
"npm:@isaacs/ttlcache@^1.4.1": "1.4.1",
|
"npm:@isaacs/ttlcache@^1.4.1": "1.4.1",
|
||||||
|
"npm:@jcayzac/image-information@1.1.1": "1.1.1",
|
||||||
"npm:@noble/hashes@^1.4.0": "1.4.0",
|
"npm:@noble/hashes@^1.4.0": "1.4.0",
|
||||||
"npm:@noble/secp256k1@2": "2.1.0",
|
"npm:@noble/secp256k1@2": "2.1.0",
|
||||||
"npm:@scure/base@^1.1.6": "1.1.6",
|
"npm:@scure/base@^1.1.6": "1.1.6",
|
||||||
"npm:@scure/bip32@^1.4.0": "1.4.0",
|
"npm:@scure/bip32@^1.4.0": "1.4.0",
|
||||||
"npm:@scure/bip39@^1.3.0": "1.3.0",
|
"npm:@scure/bip39@^1.3.0": "1.3.0",
|
||||||
"npm:@types/node@*": "18.16.19",
|
"npm:@types/node@*": "18.16.19",
|
||||||
|
"npm:blurhash@2.0.5": "2.0.5",
|
||||||
"npm:comlink-async-generator@*": "0.0.1",
|
"npm:comlink-async-generator@*": "0.0.1",
|
||||||
"npm:comlink-async-generator@^0.0.1": "0.0.1",
|
"npm:comlink-async-generator@^0.0.1": "0.0.1",
|
||||||
"npm:comlink@^4.4.1": "4.4.1",
|
"npm:comlink@^4.4.1": "4.4.1",
|
||||||
|
|
@ -658,6 +660,12 @@
|
||||||
"@isaacs/ttlcache@1.4.1": {
|
"@isaacs/ttlcache@1.4.1": {
|
||||||
"integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="
|
"integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="
|
||||||
},
|
},
|
||||||
|
"@jcayzac/image-information@1.1.1": {
|
||||||
|
"integrity": "sha512-WXM5RTu3tTuAPXPx4ytbywjqTxnjBUWM1sY+7A9UPqPwQbM9V3jkY/rzo1OJ6VYSpogFdK4cyc+o9FZFZLW+nw==",
|
||||||
|
"dependencies": [
|
||||||
|
"image-size"
|
||||||
|
]
|
||||||
|
},
|
||||||
"@noble/ciphers@0.5.3": {
|
"@noble/ciphers@0.5.3": {
|
||||||
"integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w=="
|
"integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w=="
|
||||||
},
|
},
|
||||||
|
|
@ -769,6 +777,9 @@
|
||||||
"bintrees@1.0.2": {
|
"bintrees@1.0.2": {
|
||||||
"integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw=="
|
"integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw=="
|
||||||
},
|
},
|
||||||
|
"blurhash@2.0.5": {
|
||||||
|
"integrity": "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w=="
|
||||||
|
},
|
||||||
"braces@3.0.2": {
|
"braces@3.0.2": {
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
|
@ -987,6 +998,15 @@
|
||||||
"safer-buffer"
|
"safer-buffer"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"image-size@1.1.1": {
|
||||||
|
"integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==",
|
||||||
|
"dependencies": [
|
||||||
|
"queue"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"inherits@2.0.4": {
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
|
},
|
||||||
"is-fullwidth-code-point@4.0.0": {
|
"is-fullwidth-code-point@4.0.0": {
|
||||||
"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="
|
"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="
|
||||||
},
|
},
|
||||||
|
|
@ -1260,6 +1280,12 @@
|
||||||
"punycode@2.3.1": {
|
"punycode@2.3.1": {
|
||||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="
|
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="
|
||||||
},
|
},
|
||||||
|
"queue@6.0.2": {
|
||||||
|
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
|
||||||
|
"dependencies": [
|
||||||
|
"inherits"
|
||||||
|
]
|
||||||
|
},
|
||||||
"restore-cursor@4.0.0": {
|
"restore-cursor@4.0.0": {
|
||||||
"integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
|
"integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
|
@ -2104,12 +2130,14 @@
|
||||||
"jsr:@std/streams@0.223",
|
"jsr:@std/streams@0.223",
|
||||||
"npm:@electric-sql/pglite@~0.2.8",
|
"npm:@electric-sql/pglite@~0.2.8",
|
||||||
"npm:@isaacs/ttlcache@^1.4.1",
|
"npm:@isaacs/ttlcache@^1.4.1",
|
||||||
|
"npm:@jcayzac/image-information@1.1.1",
|
||||||
"npm:@noble/secp256k1@2",
|
"npm:@noble/secp256k1@2",
|
||||||
"npm:@scure/base@^1.1.6",
|
"npm:@scure/base@^1.1.6",
|
||||||
"npm:comlink-async-generator@^0.0.1",
|
"npm:comlink-async-generator@^0.0.1",
|
||||||
"npm:comlink@^4.4.1",
|
"npm:comlink@^4.4.1",
|
||||||
"npm:commander@12.1.0",
|
"npm:commander@12.1.0",
|
||||||
"npm:entities@^4.5.0",
|
"npm:entities@^4.5.0",
|
||||||
|
"npm:fast-blurhash@1.1.4",
|
||||||
"npm:fast-stable-stringify@1",
|
"npm:fast-stable-stringify@1",
|
||||||
"npm:formdata-helper@0.3",
|
"npm:formdata-helper@0.3",
|
||||||
"npm:hono-rate-limiter@0.3",
|
"npm:hono-rate-limiter@0.3",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
import { NUploader } from '@nostrify/nostrify';
|
import { NUploader } from '@nostrify/nostrify';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { probe } from '@jcayzac/image-information';
|
||||||
|
import { Stickynotes } from '@soapbox/stickynotes';
|
||||||
|
import { encode } from 'blurhash';
|
||||||
|
import { encodeHex } from '@std/encoding/hex';
|
||||||
|
|
||||||
|
const console = new Stickynotes('ditto:ipfs:uploader');
|
||||||
|
|
||||||
export interface IPFSUploaderOpts {
|
export interface IPFSUploaderOpts {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
|
@ -7,6 +13,19 @@ export interface IPFSUploaderOpts {
|
||||||
fetch?: typeof fetch;
|
fetch?: typeof fetch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toByteArray(f: File): Promise<Uint8Array> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('loadend', (m) => {
|
||||||
|
if (m?.target?.result instanceof ArrayBuffer) {
|
||||||
|
resolve(new Uint8Array(m.target.result));
|
||||||
|
} else reject('Error loading file: readAsArrayBufferFailed');
|
||||||
|
});
|
||||||
|
reader.addEventListener('error', (e) => reject(e));
|
||||||
|
reader.readAsArrayBuffer(f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPFS uploader. It expects an IPFS node up and running.
|
* IPFS uploader. It expects an IPFS node up and running.
|
||||||
* It will try to connect to `http://localhost:5001` by default,
|
* It will try to connect to `http://localhost:5001` by default,
|
||||||
|
|
@ -36,13 +55,29 @@ export class IPFSUploader implements NUploader {
|
||||||
});
|
});
|
||||||
|
|
||||||
const { Hash: cid } = IPFSUploader.schema().parse(await response.json());
|
const { Hash: cid } = IPFSUploader.schema().parse(await response.json());
|
||||||
|
const tags: [['url', string], ...string[][]] = [
|
||||||
return [
|
|
||||||
['url', new URL(`/ipfs/${cid}`, this.baseUrl).toString()],
|
['url', new URL(`/ipfs/${cid}`, this.baseUrl).toString()],
|
||||||
['m', file.type],
|
['m', file.type],
|
||||||
['cid', cid],
|
['cid', cid],
|
||||||
['size', file.size.toString()],
|
['size', file.size.toString()],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const buffer = await toByteArray(file);
|
||||||
|
const hash = await crypto.subtle.digest('SHA-256', buffer).then(encodeHex);
|
||||||
|
tags.push(['x', hash], ['ox', hash]);
|
||||||
|
const metadata = probe(buffer);
|
||||||
|
if (metadata) {
|
||||||
|
// sane default from https://github.com/woltapp/blurhash readme
|
||||||
|
const blurhash = encode(new Uint8ClampedArray(buffer), metadata.width, metadata.height, 4, 4);
|
||||||
|
tags.push(['blurhash', blurhash]);
|
||||||
|
tags.push(['dim', `${metadata.width}x${metadata.height}`]);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error parsing ipfs metadata: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(cid: string, opts?: { signal?: AbortSignal }): Promise<void> {
|
async delete(cid: string, opts?: { signal?: AbortSignal }): Promise<void> {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue