add upload form & script
This commit is contained in:
parent
ab0d215f6a
commit
78da18a80b
BIN
site/i/t_192.png
Normal file
BIN
site/i/t_192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
site/i/t_48.png
Normal file
BIN
site/i/t_48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
BIN
site/i/t_96.png
Normal file
BIN
site/i/t_96.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
184
site/index.html
Normal file
184
site/index.html
Normal file
@ -0,0 +1,184 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>media</title>
|
||||
<link rel="shortcut icon" type="image/ico" href="" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta name="keywords" content="media" />
|
||||
<meta name="description" content="PWA, Web PWA, Web App" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Window-target" content="_top" />
|
||||
<meta http-equiv="content-Type" content="text/html;charset=utf-8" />
|
||||
<meta http-equiv="Content-Language" content="en" />
|
||||
<meta http-equiv="imagetoolbar" content="false" />
|
||||
<link rel="icon" sizes="192x192" href="./i/t_192.png" />
|
||||
<link rel="apple-touch-icon" href="./i/t_96.png" />
|
||||
<meta name="msapplication-square310x310logo" content="./i/t_96.png" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<link rel="apple-touch-startup-image" href="./i/t_192.png" />
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
|
||||
<style type="text/css">
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker
|
||||
.register("./sw.js")
|
||||
.then(function (registration) {
|
||||
console.log(
|
||||
"ServiceWorker registration successful with scope: ",
|
||||
registration.scope
|
||||
);
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log("ServiceWorker registration failed: ", err);
|
||||
});
|
||||
}
|
||||
window.addEventListener("beforeinstallprompt", function (e) {
|
||||
e.userChoice.then(function (choiceResult) {
|
||||
console.log(choiceResult.outcome);
|
||||
if (choiceResult.outcome == "dismissed") {
|
||||
console.log("User cancelled home screen install");
|
||||
} else {
|
||||
console.log("User added to home screen");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p style="color:red">!! Please report errors, bugs and weird shit to Hajamieli !!</p>
|
||||
|
||||
<form id="userform" method="POST" enctype="multipart/form-data">
|
||||
<h3>Upload a file</h3>
|
||||
<div id="upload-preview"></div>
|
||||
<div id="field"><label class="label"><input type="file" multiple="true" accept="image/*,video/*,.pdf,.epub" name="media"><span>Select an file</span></label></div>
|
||||
<input id="submit" type="submit" name="upload" value="Upload">
|
||||
</form>
|
||||
|
||||
<p>styles coming soon? propably...</p>
|
||||
<div id="results"></div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
const form = document.getElementById("userform")
|
||||
const submit = document.getElementById("submit")
|
||||
const results = document.getElementById("results")
|
||||
|
||||
const chunksize = 1000000;
|
||||
|
||||
const splitter = (file, hash) => {
|
||||
let numberofChunks = Math.ceil(file.byteLength/chunksize);
|
||||
let left = 0
|
||||
let chunks = []
|
||||
|
||||
for (let i = 0; i < numberofChunks; i++) {
|
||||
const chunkForm = new FormData();
|
||||
let contentRange = "";
|
||||
let chunk;
|
||||
if(left+chunksize <= file.byteLength){
|
||||
contentRange = `${left}-${left+chunksize}`
|
||||
chunk = file.slice(left,left+chunksize)
|
||||
left += chunksize
|
||||
} else {
|
||||
contentRange = `${left}-${file.byteLength}`
|
||||
chunk = file.slice(left,file.byteLength)
|
||||
}
|
||||
chunkForm.append('file', new Blob([chunk], {type:"video/webm"}))
|
||||
|
||||
chunks.push(
|
||||
fetch("/uploadchunk", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Number": i,
|
||||
"Content-Range": `bytes ${contentRange}/${file.byteLength}`,
|
||||
"File-Hash": hash
|
||||
},
|
||||
body: chunkForm
|
||||
}).then(res => Promise.resolve(res.status))
|
||||
)
|
||||
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
async function digest(data){
|
||||
|
||||
const hash = await crypto.subtle.digest("SHA-256", data);
|
||||
return hash
|
||||
|
||||
}
|
||||
|
||||
const processFile = file => {
|
||||
const fr = new FileReader()
|
||||
fr.readAsArrayBuffer(file)
|
||||
|
||||
fr.addEventListener("loadend", e => {
|
||||
digest(e.target.result).then(digestBuffer => {
|
||||
const hashAsString = Array.from(new Uint8Array(digestBuffer)).map((b) => b.toString(16).padStart(2, "0")).join(""); // hex the buffer for readability
|
||||
|
||||
let details = JSON.stringify({"usercode": "anonymous", "hash": hashAsString, "size": file.size, "type": file.type})
|
||||
|
||||
fetch(`/announce`, {
|
||||
method: "POST",
|
||||
headers:{
|
||||
"Content-Type": "json",
|
||||
},
|
||||
body: details
|
||||
})
|
||||
.then(res => {
|
||||
if(res.status == 200){
|
||||
Promise.all(splitter(e.target.result,hashAsString))
|
||||
.then((values) => {
|
||||
if(values.every(x => x === 200)){
|
||||
fetch(`/finish`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "json",
|
||||
},
|
||||
body: details
|
||||
}).then(res => res.json())
|
||||
.then(res => {
|
||||
console.log(res)
|
||||
results.innerHTML += `<a href="/${res.file}">https://i.hjmt.xyz/${res.file}</a><br>`
|
||||
})
|
||||
}else{
|
||||
alert("upload failed")
|
||||
}
|
||||
})
|
||||
}else if(res.status == 409){
|
||||
alert("file exists!")
|
||||
}else if(res.status == 403){
|
||||
alert("get a usertoken for bigger files")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
submit.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
for (const file of form.media.files){
|
||||
processFile(file)
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
28
site/manifest.json
Normal file
28
site/manifest.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"short_name": "hajamedia",
|
||||
"name": "hajamielis file hosting app",
|
||||
"description": "upload files",
|
||||
"version": "0.1",
|
||||
"background_color": "#010e1c",
|
||||
"theme_color": "#010e1c",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./i/t_48.png",
|
||||
"type": "image/png",
|
||||
"sizes": "48x48"
|
||||
},
|
||||
{
|
||||
"src": "./i/t_96.png",
|
||||
"type": "image/png",
|
||||
"sizes": "96x96"
|
||||
},
|
||||
{
|
||||
"src": "./i/t_192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
}
|
||||
],
|
||||
"start_url": "/"
|
||||
}
|
84
site/script.js
Normal file
84
site/script.js
Normal file
@ -0,0 +1,84 @@
|
||||
const form = document.getElementById("userform")
|
||||
const submit = document.getElementById("submit")
|
||||
const results = document.getElementById("results")
|
||||
|
||||
const chunksize = 1000000;
|
||||
|
||||
const splitter = (file, hash) => {
|
||||
let numberofChunks = Math.ceil(file.byteLength/chunksize);
|
||||
let left = 0
|
||||
let chunks = []
|
||||
|
||||
for (let i = 0; i < numberofChunks; i++) {
|
||||
const chunkForm = new FormData();
|
||||
let contentRange = "";
|
||||
let chunk;
|
||||
if(left+chunksize <= file.byteLength){
|
||||
contentRange = `${left}-${left+chunksize}`
|
||||
chunk = file.slice(left,left+chunksize)
|
||||
left += chunksize
|
||||
} else {
|
||||
contentRange = `${left}-${file.byteLength}`
|
||||
chunk = file.slice(left,file.byteLength)
|
||||
}
|
||||
chunkForm.append('file', new Blob([chunk], {type:"video/webm"}))
|
||||
|
||||
chunks.push(
|
||||
fetch("/test", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Number": i,
|
||||
"Content-Range": `bytes ${contentRange}/${file.byteLength}`,
|
||||
"File-Hash": hash
|
||||
},
|
||||
body: chunkForm
|
||||
}))
|
||||
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
async function digest(data){
|
||||
|
||||
const hash = await crypto.subtle.digest("SHA-256", data);
|
||||
return hash
|
||||
|
||||
}
|
||||
|
||||
const processFile = file => {
|
||||
const fr = new FileReader()
|
||||
fr.readAsArrayBuffer(file)
|
||||
|
||||
fr.addEventListener("loadend", e => {
|
||||
|
||||
digest(e.target.result).then(digestBuffer => {
|
||||
|
||||
const hashAsString = Array.from(new Uint8Array(digestBuffer)).map((b) => b.toString(16).padStart(2, "0")).join(""); // hex the buffer for readability
|
||||
|
||||
Promise.all(splitter(e.target.result,hashAsString))
|
||||
.then((values) => {
|
||||
fetch(`/finish`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "json",
|
||||
},
|
||||
body: JSON.stringify({"hash": hashAsString, "type": file.type})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
submit.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
let fd = new FormData();
|
||||
|
||||
for (const file of form.media.files){
|
||||
|
||||
processFile(file)
|
||||
|
||||
fd.append('file', file)
|
||||
console.log(file)
|
||||
}
|
||||
})
|
3
site/sw.js
Normal file
3
site/sw.js
Normal file
@ -0,0 +1,3 @@
|
||||
self.addEventListener("fetch", function(event) {
|
||||
console.log(`start server worker`)
|
||||
});
|
Loading…
Reference in New Issue
Block a user