Cybrkyd's Git Repositories

go-share - commit: 9219096

commit 9219096f96f4f138b2d8d3fce872436626a3bcb7bf43ea78c0d4b23c6d9a4463
author cybrkyd <git@cybrkyd.com> 2026-05-22 19:44:49 +0100
committer cybrkyd <git@cybrkyd.com> 2026-05-22 19:44:49 +0100

Commit Message

main.go

📊 Diffstat

main.go 202
1 files changed, 202 insertions(+), 0 deletions(-)

Diff

diff --git a/main.go b/main.go
new file mode 100644
index 0000000..dc2a1f9
--- /dev/null
+++ b/main.go
@@ -0,0 +1,202 @@
+ package main
+
+ import (
+ "fmt"
+ "html"
+ "io"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+ )
+
+ const uploadFolder = "./uploads"
+
+ func getBaseHTML(title, content string) string {
+ return fmt.Sprintf(`<!doctype html>
+ <html>
+ <head>
+ <title>%s</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
+ <style>
+ * {margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
+ html, body {width:100%%;height:100%%;overflow-x:hidden;background-color:#f5f5f5;font-family:sans-serif;}
+ body {display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;padding:20px;padding-top:env(safe-area-inset-top);padding-bottom:env(safe-area-inset-bottom);}
+ h1 {text-align:center;margin-bottom:30px;font-size:33px;color:#333;width:100%%;padding:0 10px;}
+ .container {width:100%%;max-width:400px;display:flex;flex-direction:column;align-items:center;gap:25px;}
+ form {width:100%%;display:flex;flex-direction:column;align-items:center;gap:25px;}
+ input[type="file"] {width:100%%;padding:15px;border:1px solid #008CBA;border-radius:10px;background-color:white;font-size:16px;color:#555;cursor:pointer;text-align:center;transition:all 0.3s ease;}
+ input[type="file"]:hover {background-color:#f9f9f9;border-color:#00b8f5;}
+ input[type="submit"], .button {width:100%%;padding:15px;background-color:#008CBA;color:white;border:none;border-radius:10px;font-size:18px;font-weight:600;cursor:pointer;transition:all 0.3s ease;text-align:center;text-decoration:none;display:block;}
+ input[type="submit"]:hover, .button:hover {background-color:#00b8f5;}
+ input[type="submit"]:active, .button:active {transform:translateY(2px);}
+ .file-list {width:100%%;background:white;border-radius:10px;padding:20px;}
+ .file-item {padding:10px 0;border-bottom:1px solid #eee;display:flex;justify-content:space-between;align-items:center;}
+ .file-item:last-child {border-bottom:none;}
+ .file-name {font-size:16px;color:#333;word-break:break-all;}
+ .message {width:100%%;padding:15px;background-color:#008CBA;color:white;border-radius:10px;text-align:center;margin-bottom:20px;font-size:16px;}
+ .error {background-color:#f44336;font-size:18px;font-weight:600;}
+ .navigation {display:flex;gap:15px;width:100%%;max-width:400px;margin-top:20px;}
+ .nav-button {flex:1;padding:12px;background-color:#008CBA;color:white;border-radius:10px;text-align:center;text-decoration:none;font-weight:600;transition:background-color 0.3s ease;}
+ .nav-button:hover {background-color:#00b8f5;}
+ #progress-wrap {width:100%%;display:none;flex-direction:column;gap:10px;}
+ #progress-bar-bg {width:100%%;background:#ddd;border-radius:10px;height:18px;overflow:hidden;}
+ #progress-bar {height:100%%;width:0%%;background:#008CBA;border-radius:10px;transition:width 0.2s ease;}
+ #progress-label {text-align:center;font-size:14px;color:#555;}
+ @media (max-width:480px) {
+ body {padding:15px;}
+ h1 {font-size:22px;margin-bottom:25px;}
+ input[type="file"], input[type="submit"], .button {padding:14px;}
+ .file-list {padding:15px;}
+ }
+ @media (max-width:360px) {
+ h1 {font-size:20px;}
+ input[type="file"], input[type="submit"], .button {padding:12px;font-size:15px;}
+ .navigation {flex-direction:column;gap:10px;}
+ }
+ </style>
+ </head>
+ <body>
+ <h1>%s</h1>
+ <div class="container">
+ %s
+ </div>
+ <script>
+ (function() {
+ var form = document.querySelector('form');
+ if (!form) return;
+ form.addEventListener('submit', function(e) {
+ var fileInput = form.querySelector('input[type="file"]');
+ if (!fileInput || !fileInput.files.length) return;
+ e.preventDefault();
+ var wrap = document.getElementById('progress-wrap');
+ var bar = document.getElementById('progress-bar');
+ var lbl = document.getElementById('progress-label');
+ var btn = form.querySelector('input[type="submit"]');
+ wrap.style.display = 'flex';
+ btn.disabled = true;
+ btn.style.opacity = '0.6';
+ var xhr = new XMLHttpRequest();
+ xhr.open('POST', '/', true);
+ xhr.upload.addEventListener('progress', function(ev) {
+ if (ev.lengthComputable) {
+ var pct = Math.round((ev.loaded / ev.total) * 100);
+ bar.style.width = pct + '%%';
+ lbl.textContent = pct + '%% uploaded (' + formatBytes(ev.loaded) + ' / ' + formatBytes(ev.total) + ')';
+ }
+ });
+ xhr.addEventListener('load', function() {
+ bar.style.width = '100%%';
+ lbl.textContent = 'Processing…';
+ document.open();
+ document.write(xhr.responseText);
+ document.close();
+ });
+ xhr.addEventListener('error', function() {
+ lbl.textContent = 'Upload failed. Try again.';
+ btn.disabled = false;
+ btn.style.opacity = '1';
+ });
+ var data = new FormData(form);
+ xhr.send(data);
+ });
+ function formatBytes(b) {
+ if (b < 1024) return b + ' B';
+ if (b < 1048576) return (b/1024).toFixed(1) + ' KB';
+ return (b/1048576).toFixed(1) + ' MB';
+ }
+ })();
+ </script>
+ </body>
+ </html>`, title, title, content)
+ }
+
+ func uploadHandler(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodPost {
+ if err := r.ParseMultipartForm(100 << 20); err != nil {
+ fmt.Fprint(w, getBaseHTML("Error",
+ `<div class="message error">Failed to parse form</div>`+
+ `<a href="/" class="button">Try Again</a>`))
+ return
+ }
+ defer r.MultipartForm.RemoveAll()
+
+ files := r.MultipartForm.File["files"]
+ if len(files) == 0 {
+ fmt.Fprint(w, getBaseHTML("Error",
+ `<div class="message error">No file part</div>`+
+ `<a href="/" class="button">Try Again</a>`))
+ return
+ }
+
+ if files[0].Filename == "" {
+ fmt.Fprint(w, getBaseHTML("Error",
+ `<div class="message error">No selected files</div>`+
+ `<a href="/" class="button">Try Again</a>`))
+ return
+ }
+
+ var uploaded []string
+ for _, fh := range files {
+ if fh.Filename == "" {
+ continue
+ }
+ src, err := fh.Open()
+ if err != nil {
+ continue
+ }
+ destPath := filepath.Join(uploadFolder, filepath.Base(fh.Filename))
+ dst, err := os.Create(destPath)
+ if err != nil {
+ src.Close()
+ continue
+ }
+ io.Copy(dst, src)
+ src.Close()
+ dst.Close()
+ uploaded = append(uploaded, fh.Filename)
+ }
+
+ var items strings.Builder
+ for _, name := range uploaded {
+ items.WriteString(fmt.Sprintf(
+ `<div class="file-item"><span class="file-name">%s</span></div>`,
+ html.EscapeString(name),
+ ))
+ }
+
+ fmt.Fprint(w, getBaseHTML("Upload Successful",
+ `<div class="message">Files uploaded successfully!</div>`+
+ `<div class="file-list">`+items.String()+`</div>`+
+ `<div class="navigation">`+
+ `<a href="/" class="nav-button upload">Upload More</a>`+
+ `</div>`))
+ return
+ }
+
+ fmt.Fprint(w, getBaseHTML("Upload Files",
+ `<form method="post" enctype="multipart/form-data">
+ <input type="file" name="files" multiple>
+ <div id="progress-wrap">
+ <div id="progress-bar-bg"><div id="progress-bar"></div></div>
+ <div id="progress-label">Starting upload…</div>
+ </div>
+ <input type="submit" value="Upload">
+ </form>`))
+ }
+
+ func main() {
+ if err := os.MkdirAll(uploadFolder, 0755); err != nil {
+ fmt.Fprintf(os.Stderr, "cannot create upload folder: %v\n", err)
+ os.Exit(1)
+ }
+
+ http.HandleFunc("/", uploadHandler)
+
+ fmt.Println("Listening on port 5000")
+ if err := http.ListenAndServe(":5000", nil); err != nil {
+ fmt.Fprintf(os.Stderr, "server error: %v\n", err)
+ os.Exit(1)
+ }
+ }
+