this code sucks but oh well

This commit is contained in:
split / May 2023-01-29 21:06:25 -08:00
parent 7531515e78
commit d30de18d26
8 changed files with 339 additions and 43 deletions

View file

@ -22,8 +22,9 @@ TOKEN=KILL-YOURSELF.NOW
- [X] 1.2.2 clean up this shitty code
- [X] 1.2.3 bugfixes
- [ ] 1.3.0 new ui; accounts; utility endpoints; multi file uploads
- [ ] 1.3.1 self-destruct option
- [ ] 1.3.2 disable cloning of local ips
- [ ] 1.3.1 organize svelte code
- [ ] 1.3.2 self-destructing files
- [ ] 1.3.3 disable cloning of local ips
- [ ] 1.4.0 admin panel
- [ ] 2.0.0 rewrite using theUnfunny's code as a base/rewrite using monofile-core

View file

@ -53,7 +53,13 @@ app.get("/", function(req,res) {
app.post("/upload",multerSetup.single('file'),async (req,res) => {
if (req.file) {
try {
files.uploadFile({name:req.file.originalname,mime:req.file.mimetype,uploadId:req.header("monofile-upload-id")},req.file.buffer)
let prm = req.header("monofile-params")
let params:{[key:string]:any} = {}
if (prm) {
params = JSON.parse(prm)
}
files.uploadFile({uploadId:params.uploadId,name:req.file.originalname,mime:req.file.mimetype},req.file.buffer)
.then((uID) => res.send(uID))
.catch((stat) => {
res.status(stat.status);

View file

@ -4,10 +4,6 @@
border: 1px solid gray;
padding: 0px 0px 10px 0px;
@media screen and (max-width: 500px) {
width:100%;
}
p {
font-family: "Fira Code", monospace;
text-align: left;
@ -77,6 +73,7 @@
position:relative;
background-color:#262626;
transition-duration:250ms;
input[type=file] {
opacity: 0;
@ -98,6 +95,11 @@
padding:0px;
margin: 0px;
}
&:hover {
transition-duration:250ms;
background-color:#292929;
}
}
}
}

View file

@ -0,0 +1,59 @@
// should probably start using mixins for thingss like this
#uploadWindow {
.file {
background-color:#191919;
border: 1px solid gray;
padding: 10px;
overflow:clip;
position:relative;
h2 {
font-size: 16px;
margin: 0px;
font-weight:600;
width:calc( 100% - 20px );
}
input[type=text] {
background-color:#333333;
color:#DDDDDD;
border:none;
outline:none;
padding:5px;
position:relative;
width:100%;
transition-duration:250ms;
@media screen and (max-width: 500px) {
font-size:16px;
padding:10px;
}
}
.buttonContainer {
display:flex;
column-gap:10px;
button {
flex-basis: 50%;
flex-grow: 1;
padding:5px;
}
}
.uploadingContainer {
color: #AAAAAA;
}
.hitbox {
opacity:0;
position:absolute;
left:0px;
top:0px;
height:100%;
width:100%;
}
}
}

View file

@ -1,4 +1,5 @@
@use "uploader/add_new_files";
@use "uploader/file";
#uploadWindow {
position:absolute;
@ -6,8 +7,13 @@
top:50%;
transform:translate(-50%,-50%);
padding:10px 15px 10px 15px;
display:flex;
flex-direction: column;
width:350px;
@media screen and (min-width:500px) {
max-height: calc( 100% - 80px );
}
background-color:#222222;
color:#ddd;
@ -30,6 +36,32 @@
font-family: "Inconsolata", monospace;
}
.uploadContainer {
overflow:auto;
}
button {
cursor:pointer;
background-color:#393939;
color:#DDDDDD;
border:none;
outline:none;
padding:5px;
transition-duration: 250ms;
/*overflow:clip;*/
@media screen and (max-width: 500px) {
font-size:16px;
padding:10px;
}
&:hover {
transition-duration: 250ms;
background-color:#434343;
color: #ffffff;
}
}
@media screen and (max-width: 500px) {
width: calc( 100% - 20px );
height: calc( 100% - 20px );

View file

@ -1,19 +1,145 @@
<script>
// stats
import { _void } from "./transition/_void.js";
import { fade } from "svelte/transition";
import { circIn, circOut } from "svelte/easing";
import AttachmentZone from "./uploader/AttachmentZone.svelte";
// stats
let ServerStats = {}
fetch("/server").then(async (data) => {
ServerStats = await data.json()
})
let refresh_stats = () => {
fetch("/server").then(async (data) => {
ServerStats = await data.json()
})
}
refresh_stats()
// uploads
let attachmentZone;
let uploads = new Map()
let uploads = {};
let uploadInProgress = false;
let handle_file_upload = (ev) => {
if (ev.detail.type == "clone") {
uploads[Math.random().toString().slice(2)] = {
type: "clone",
name: ev.detail.url,
url: ev.detail.url,
params: {
uploadId: ""
},
uploadStatus:{
fileId: null,
error: null,
}
}
uploads = uploads
} else if (ev.detail.type == "upload") {
ev.detail.files.forEach((v,x) => {
uploads[Math.random().toString().slice(2)] = {
type: "upload",
name: v.name,
file: v,
params: {
uploadId: ""
},
uploadStatus:{
fileId: null,
error: null,
}
}
})
uploads = uploads
}
}
let handle_fetch_promise = (x,prom) => {
return prom.then(async (res) => {
let txt = await res.text()
if (txt.startsWith("[err]")) uploads[x].uploadStatus.error = txt;
else {
uploads[x].uploadStatus.fileId = txt;
refresh_stats();
}
}).catch((err) => {
uploads[x].uploadStatus.error = err.toString();
})
}
let upload_files = () => {
uploadInProgress = true
// go through all files
Object.entries(uploads).forEach(([x,v]) => {
switch(v.type) {
case "upload":
let fd = new FormData()
fd.append("file",v.file)
handle_fetch_promise(x,fetch("/upload",{
headers: {
"monofile-params": JSON.stringify(v.params)
},
method: "POST",
body: fd
}))
break
case "clone":
handle_fetch_promise(x,fetch("/clone",{
method: "POST",
body: JSON.stringify({
url: v.url,
...v.params
})
}))
break
}
})
}
// animation
function padding_scaleY(node, { duration, easingFunc, padY, padX, op }) {
let rect = node.getBoundingClientRect()
return {
duration: duration||300,
css: t => {
let eased = (easingFunc || circOut)(t)
return `
height: ${eased*(rect.height-(padY||0))}px;
${padX&&padY ? `padding: ${(eased)*(padY)}px ${(padX)}px;` : ""}
${op ? `opacity: ${eased};` : ""}
`
}
}
}
function fileTransition(node) {
return {
duration: 300,
css: t => {
let eased = circOut(t)
return `
height: ${eased*(node.offsetHeight-20)}px;
padding: ${eased*10}px 10px;
`
}
}
}
</script>
@ -23,21 +149,75 @@
<span class="number">{ServerStats.version ? `v${ServerStats.version}` : "•••"}</span>&nbsp;&nbsp—&nbsp;&nbsp;Discord based file sharing
</p>
<div>
{#each Array.from(uploads.entries()) as upload (upload[0])}
<div class="file">
<div style:min-height="10px" />
<!-- consider splitting the file thing into a separate element maybe -->
<div class="uploadContainer">
{#each Object.entries(uploads) as upload (upload[0])}
<!-- container to allow for animate directive -->
<div>
<div class="file" transition:fileTransition style:border={upload[1].uploadStatus.error ? "1px solid #BB7070" : ""}>
<h2>{upload[1].name} <span style:color="#999999" style:font-weight="400">{upload[1].type}{@html upload[1].type == "upload" ? `&nbsp;(${Math.round(upload[1].file.size/1048576)}MB)` : ""}</span></h2>
{#if upload[1].maximized && !uploadInProgress}
<div transition:padding_scaleY|local>
<div style:height="10px" />
<input placeholder="custom id" type="text" bind:value={ uploads[upload[0]].params.uploadId }>
<div style:height="10px" />
<div class="buttonContainer">
<button on:click={() => {delete uploads[upload[0]];uploads=uploads;}}>
delete
</button>
<button on:click={() => uploads[upload[0]].maximized = false}>
minimize
</button>
</div>
</div>
{:else if !uploadInProgress}
<button on:click={() => uploads[upload[0]].maximized = true} class="hitbox"></button>
{:else}
<div transition:padding_scaleY|local class="uploadingContainer">
{#if !upload[1].uploadStatus.fileId}
<p in:fade={{duration:300, delay:400, easingFunc:circOut}} out:padding_scaleY={{easingFunc:circIn,op:true}}>{upload[1].uploadStatus.error ?? "Uploading..."}</p>
{/if}
{#if upload[1].uploadStatus.fileId}
<div style:height="10px" transition:padding_scaleY />
{#if !upload[1].viewingUrl}
<div class="buttonContainer" out:_void in:_void={{easingFunc:circOut}}>
<button on:click={() => uploads[upload[0]].viewingUrl = true}>
view url
</button>
<button on:click={() => navigator.clipboard.writeText(`https://${window.location.host}/download/${upload[1].uploadStatus.fileId}`)}>
copy url
</button>
</div>
{:else}
<div class="buttonContainer" out:_void in:_void={{easingFunc:circOut}}>
<input type="text" readonly value={`https://${window.location.host}/download/${upload[1].uploadStatus.fileId}`} style:flex-basis="80%">
<button on:click={() => uploads[upload[0]].viewingUrl = false} style:flex-basis="20%">
ok
</button>
</div>
{/if}
{/if}
</div>
{/if}
</div>
<div style:height="10px" transition:padding_scaleY />
</div>
{/each}
</div>
<div style:height="10px" />
{#if uploads.size < 1}
<AttachmentZone bind:this={attachmentZone}/>
{#if uploadInProgress == false}
<AttachmentZone bind:this={attachmentZone} on:addFiles={handle_file_upload}/>
<div style:min-height="10px" transition:padding_scaleY />
{#if Object.keys(uploads).length > 0}
<button in:padding_scaleY={{easingFunc:circOut}} out:_void on:click={upload_files}>upload</button>
<div transition:_void style:min-height="10px" />
{/if}
{/if}
<div style:height="10px" />
<p style:color="#999999" style:text-align="center">
Hosting <span class="number" style:font-weight="600">{ServerStats.files || "•••"}</span> files
@ -47,7 +227,7 @@
</p>
<p style:color="#999999" style:text-align="center" style:font-size="12px">
Made with ❤ by <a href="https://github.com/nbitzz" style:font-size="12px">@nbitzz</a><a href="https://github.com/nbitzz/monofile" style:font-size="12px">source</a>
Made with {Math.floor(Math.random()*10)==0 ? "🐟" : ""} by <a href="https://github.com/nbitzz" style:font-size="12px">@nbitzz</a><a href="https://github.com/nbitzz/monofile" style:font-size="12px">source</a>
</p>
<div style:height="10px" />
</div>

View file

@ -0,0 +1,20 @@
import { circIn, circOut } from "svelte/easing"
export function _void(node, { duration, easingFunc, op }) {
let rect = node.getBoundingClientRect()
return {
duration: duration||300,
css: t => {
let eased = (easingFunc || circIn)(t)
return `
white-space: nowrap;
height: ${(eased)*(rect.height)}px;
padding: 0px;
opacity:${eased};
overflow: clip;
`
}
}
}

View file

@ -1,5 +1,7 @@
<script>
import { createEventDispatcher } from "svelte";
import { circIn, circOut } from "svelte/easing"
import { _void } from "../transition/_void"
let uploadTypes = {
files: 1,
@ -7,32 +9,22 @@
}
let uploadType = undefined
function _void(node, { duration, easingFunc, op }) {
let rect = node.getBoundingClientRect()
return {
duration: duration||300,
css: t => {
let eased = (easingFunc || circIn)(t)
return `
white-space: nowrap;
height: ${(eased)*(rect.height)}px;
padding: 0px;
opacity:${eased};
overflow: clip;
`
}
}
}
let dispatch = createEventDispatcher();
// file upload
/**
* @type HTMLInputElement
*/
let fileUpload;
$: {
if (fileUpload) {
fileUpload.addEventListener("change",() => {
dispatch("addFiles",{
type: "upload",
files: Array.from(fileUpload.files)
})
uploadType = undefined
})
}
@ -53,6 +45,10 @@
if (cloneButton && cloneUrlTextbox) {
cloneButton.addEventListener("click",() => {
if (cloneUrlTextbox.value) {
dispatch("addFiles",{
type: "clone",
url: cloneUrlTextbox.value
})
uploadType = undefined;
} else {
cloneUrlTextbox.animate([