void-cat-rs/ui/index.html
Kieran 7fa2633a1e
All checks were successful
continuous-integration/drone/push Build is passing
Blossom fixes
2024-08-30 22:00:33 +01:00

184 lines
5.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>void_cat_rs</title>
<style>
html {
background-color: black;
color: white;
font-size: 15px;
font-weight: 400;
font-family: Arial, serif;
}
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.gap-2 {
gap: 0.5rem;
}
</style>
<script>
async function dumpToLog(rsp) {
console.debug(rsp);
const text = await rsp.text();
if (rsp.ok) {
document.querySelector("#log").append(JSON.stringify(JSON.parse(text), undefined, 2));
} else {
document.querySelector("#log").append(text);
}
document.querySelector("#log").append("\n");
}
async function listFiles() {
try {
const auth_event = await window.nostr.signEvent({
kind: 27235,
created_at: Math.floor(new Date().getTime() / 1000),
content: "",
tags: [
["u", `${window.location.protocol}//${window.location.host}/n96`],
["method", "GET"]
]
});
const rsp = await fetch("/n96?page=0&count=100", {
method: "GET",
headers: {
accept: "application/json",
authorization: `Nostr ${btoa(JSON.stringify(auth_event))}`,
},
});
await dumpToLog(rsp);
} catch (e) {
}
}
async function uploadFiles(e) {
try {
const input = document.querySelector("#file");
const file = input.files[0];
console.debug(file);
const r_nip96 = document.querySelector("#method-nip96").checked;
const r_blossom = document.querySelector("#method-blossom").checked;
if (r_nip96) {
await uploadFilesNip96(file)
} else if (r_blossom) {
await uploadBlossom(file);
}
} catch (ex) {
if (ex instanceof Error) {
alert(ex.message);
}
}
}
function buf2hex(buffer) { // buffer is an ArrayBuffer
return [...new Uint8Array(buffer)]
.map(x => x.toString(16).padStart(2, '0'))
.join('');
}
async function uploadBlossom(file) {
const hash = await window.crypto.subtle.digest("SHA-256", await file.arrayBuffer());
const now = Math.floor(new Date().getTime() / 1000);
const auth_event = await window.nostr.signEvent({
kind: 24242,
created_at: now,
content: `Upload ${file.name}`,
tags: [
["t", "upload"],
["u", `${window.location.protocol}//${window.location.host}/upload`],
["x", buf2hex(hash)],
["method", "PUT"],
["expiration", (now + 10).toString()]
]
});
const rsp = await fetch("/upload", {
body: file,
method: "PUT",
headers: {
accept: "application/json",
authorization: `Nostr ${btoa(JSON.stringify(auth_event))}`,
},
});
await dumpToLog(rsp);
}
async function uploadFilesNip96(file) {
const fd = new FormData();
fd.append("size", file.size.toString());
fd.append("caption", file.name);
fd.append("media_type", file.type);
fd.append("file", file);
fd.append("no_transform", document.querySelector("#no_transform").checked.toString())
const auth_event = await window.nostr.signEvent({
kind: 27235,
created_at: Math.floor(new Date().getTime() / 1000),
content: "",
tags: [
["u", `${window.location.protocol}//${window.location.host}/n96`],
["method", "POST"]
]
});
const rsp = await fetch("/n96", {
body: fd,
method: "POST",
headers: {
accept: "application/json",
authorization: `Nostr ${btoa(JSON.stringify(auth_event))}`,
},
});
await dumpToLog(rsp);
}
</script>
</head>
<body>
<h1>
Welcome to void_cat_rs
</h1>
<div class="flex flex-col gap-2">
<div>
<label>
NIP-96
<input type="radio" name="method" id="method-nip96"/>
</label>
<label>
Blossom
<input type="radio" name="method" id="method-blossom"/>
</label>
</div>
<div style="color: #ff8383;">
You must have a nostr extension for this to work
</div>
<input type="file" id="file">
<div>
<input type="checkbox" id="no_transform">
<label for="no_transform">
Disable compression (images)
</label>
</div>
<div>
<button type="submit" onclick="uploadFiles(event)">
Upload
</button>
</div>
<div>
<button type="submit" onclick="listFiles()">
List Uploads
</button>
</div>
</div>
<pre id="log"></pre>
</body>
</html>