uploads

Log | Files | Refs

commit 65e9032175a280768229a018c471714084792c89
parent e095fb98f5b2389794d3487c5d91003f50d2455e
Author: Amit Dutta <mail@amit.is-a.dev>
Date:   Tue, 21 Jul 2026 09:03:43 +0530

Create docs.html
Diffstat:
Adocs.html | 305++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 305 insertions(+), 0 deletions(-)

diff --git a/docs.html b/docs.html @@ -0,0 +1,305 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Docs &middot; Upload Hub</title> + + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap" rel="stylesheet"> + <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,1,0" rel="stylesheet" /> + + <script src="https://cdn.tailwindcss.com"></script> + <script> + tailwind.config = { + theme: { + extend: { + fontFamily: { sans: ['Lexend', 'sans-serif'] }, + colors: { + m3: { + background: '#FDFCFB', backgroundDark: '#1A1C19', + surfaceContainer: '#F1F1EA', surfaceContainerDark: '#2D2F2B', + surfaceContainerHigh: '#EBEBE4', surfaceContainerHighDark: '#333531', + surfaceContainerHighest: '#E5E6DE', surfaceContainerHighestDark: '#434541', + onSurface: '#1A1C19', onSurfaceDark: '#E3E3DC', + onSurfaceVariant: '#43483E', onSurfaceVariantDark: '#C3C8BC', + primary: '#386A20', primaryDark: '#9CD67D', + onPrimary: '#FFFFFF', onPrimaryDark: '#0C3900', + secondaryContainer: '#D7E8CD', secondaryContainerDark: '#374B2E', + onSecondaryContainer: '#111F0F', onSecondaryContainerDark: '#D7E8CD', + outline: '#74796D', outlineDark: '#8D9286', + } + } + } + } + } + </script> + + <style> + body { background-color: #FDFCFB; margin: 0; -webkit-font-smoothing: antialiased; } + @media (prefers-color-scheme: dark) { body { background-color: #1A1C19; } } + .diagram-box { background: #F1F1EA; } + @media (prefers-color-scheme: dark) { .diagram-box { background: #2D2F2B; } } + .node { fill: #D7E8CD; stroke: #386A20; } + @media (prefers-color-scheme: dark) { .node { fill: #374B2E; stroke: #9CD67D; } } + .node-alt { fill: #E5E6DE; stroke: #74796D; } + @media (prefers-color-scheme: dark) { .node-alt { fill: #434541; stroke: #8D9286; } } + .node-text { fill: #111F0F; font-family: 'Lexend', sans-serif; font-size: 12px; font-weight: 600; } + @media (prefers-color-scheme: dark) { .node-text { fill: #D7E8CD; } } + .node-text-alt { fill: #1A1C19; font-family: 'Lexend', sans-serif; font-size: 12px; font-weight: 500; } + @media (prefers-color-scheme: dark) { .node-text-alt { fill: #E3E3DC; } } + .arrow { stroke: #74796D; stroke-width: 2; fill: none; marker-end: url(#arrowhead); } + @media (prefers-color-scheme: dark) { .arrow { stroke: #8D9286; } } + .arrow-label { fill: #43483E; font-family: 'Lexend', sans-serif; font-size: 10px; } + @media (prefers-color-scheme: dark) { .arrow-label { fill: #C3C8BC; } } + code { background: #E5E6DE; padding: 2px 6px; border-radius: 4px; font-size: 0.85em; } + @media (prefers-color-scheme: dark) { code { background: #434541; } } + </style> +</head> +<body class="bg-m3-background dark:bg-m3-backgroundDark text-m3-onSurface dark:text-m3-onSurfaceDark font-sans"> + +<div class="max-w-[720px] mx-auto px-4 py-10"> + + <a href="/" class="inline-flex items-center gap-1 text-sm font-semibold text-m3-primary dark:text-m3-primaryDark mb-6"> + <span class="material-symbols-outlined text-[18px]">arrow_back</span> Back to Upload + </a> + + <h1 class="text-3xl font-bold tracking-tight mb-2">How this tool works</h1> + <p class="text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark mb-10"> + A permanent, free file host built on a Hugging Face dataset repo, served through a serverless + FastAPI backend on Vercel. Here's exactly what happens behind each button. + </p> + + <!-- ===================== Section: Architecture ===================== --> + <section class="mb-14"> + <h2 class="text-xl font-bold mb-3">1. The building blocks</h2> + <p class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark mb-4"> + There are three pieces: the <strong>frontend</strong> (this website, plain HTML/JS), the + <strong>backend</strong> (a Python FastAPI app running as a Vercel serverless function), and + <strong>storage</strong> (a public Hugging Face dataset repo, which gives ~unlimited free storage + and a permanent, directly-linkable URL per file). + </p> + <div class="diagram-box rounded-[20px] p-4 overflow-x-auto"> + <svg viewBox="0 0 680 140" xmlns="http://www.w3.org/2000/svg" class="min-w-[600px]"> + <defs> + <marker id="arrowhead" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"> + <path d="M0,0 L8,4 L0,8 Z" class="node-alt" /> + </marker> + </defs> + <rect x="20" y="45" width="150" height="50" rx="12" class="node-alt"/> + <text x="95" y="65" text-anchor="middle" class="node-text-alt">Browser</text> + <text x="95" y="80" text-anchor="middle" class="node-text-alt" font-size="10">index.html</text> + + <rect x="265" y="45" width="150" height="50" rx="12" class="node"/> + <text x="340" y="65" text-anchor="middle" class="node-text">FastAPI backend</text> + <text x="340" y="80" text-anchor="middle" class="node-text" font-size="10">index.py (Vercel)</text> + + <rect x="510" y="45" width="150" height="50" rx="12" class="node-alt"/> + <text x="585" y="65" text-anchor="middle" class="node-text-alt">HF Dataset</text> + <text x="585" y="80" text-anchor="middle" class="node-text-alt" font-size="10">notamitgamer/uploads</text> + + <path d="M170,65 L265,65" class="arrow"/> + <text x="217" y="55" text-anchor="middle" class="arrow-label">HTTP request</text> + <path d="M415,65 L510,65" class="arrow"/> + <text x="462" y="55" text-anchor="middle" class="arrow-label">HF API</text> + </svg> + </div> + </section> + + <!-- ===================== Section: Regular upload ===================== --> + <section class="mb-14"> + <h2 class="text-xl font-bold mb-3">2. Uploading a file</h2> + <p class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark mb-4"> + Drop a file (or several, or paste one) and the browser sends it straight to <code>/api/upload</code> + as <code>multipart/form-data</code>. No file ever touches disk on the server &mdash; it's read into memory + and streamed to Hugging Face. + </p> + <div class="diagram-box rounded-[20px] p-4 overflow-x-auto mb-4"> + <svg viewBox="0 0 680 320" xmlns="http://www.w3.org/2000/svg" class="min-w-[600px]"> + <rect x="20" y="10" width="200" height="40" rx="10" class="node-alt"/> + <text x="120" y="35" text-anchor="middle" class="node-text-alt">Select / drop / paste file(s)</text> + + <path d="M120,50 L120,80" class="arrow"/> + <rect x="20" y="80" width="200" height="40" rx="10" class="node-alt"/> + <text x="120" y="105" text-anchor="middle" class="node-text-alt">POST /api/upload</text> + + <path d="M120,120 L120,150" class="arrow"/> + <rect x="20" y="150" width="200" height="50" rx="10" class="node"/> + <text x="120" y="170" text-anchor="middle" class="node-text">Sanitize custom_id</text> + <text x="120" y="184" text-anchor="middle" class="node-text" font-size="10">or generate random ID</text> + + <path d="M120,200 L120,230" class="arrow"/> + <rect x="20" y="230" width="200" height="40" rx="10" class="node"/> + <text x="120" y="255" text-anchor="middle" class="node-text">Upload bytes to HF dataset</text> + + <path d="M220,250 L340,250" class="arrow"/> + <rect x="340" y="230" width="200" height="60" rx="10" class="node"/> + <text x="440" y="252" text-anchor="middle" class="node-text">Expiry chosen?</text> + <text x="440" y="268" text-anchor="middle" class="node-text" font-size="10">write item.meta.json</text> + <text x="440" y="280" text-anchor="middle" class="node-text" font-size="10">with expires_at</text> + + <path d="M440,290 L440,310 L120,310 L120,300" class="arrow"/> + <text x="280" y="305" text-anchor="middle" class="arrow-label">return link to browser</text> + </svg> + </div> + <ul class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark list-disc pl-5 space-y-1"> + <li>Any file extension is accepted &mdash; the server never inspects file type, only reuses the extension for the generated ID.</li> + <li>Max size is <strong>~4.4&nbsp;MB</strong> per file, kept just under Vercel's hard 4.5&nbsp;MB request-body limit.</li> + <li>A custom ID is only allowed when uploading exactly one file, and is sanitized to <code>[a-zA-Z0-9._-]</code> to block path traversal.</li> + </ul> + </section> + + <!-- ===================== Section: Link types ===================== --> + <section class="mb-14"> + <h2 class="text-xl font-bold mb-3">3. Permanent link vs. expiring link</h2> + <p class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark mb-4"> + The link you get back depends on whether you picked an expiry. This matters because it changes + how the link is served when someone opens it later. + </p> + <div class="diagram-box rounded-[20px] p-4 overflow-x-auto mb-4"> + <svg viewBox="0 0 680 260" xmlns="http://www.w3.org/2000/svg" class="min-w-[600px]"> + <rect x="250" y="10" width="180" height="40" rx="10" class="node-alt"/> + <text x="340" y="35" text-anchor="middle" class="node-text-alt">Someone opens the link</text> + + <path d="M310,50 L150,90" class="arrow"/> + <text x="200" y="70" text-anchor="middle" class="arrow-label">no expiry set</text> + <path d="M370,50 L530,90" class="arrow"/> + <text x="480" y="70" text-anchor="middle" class="arrow-label">expiry set</text> + + <rect x="30" y="90" width="240" height="40" rx="10" class="node"/> + <text x="150" y="115" text-anchor="middle" class="node-text">/&lt;item_id&gt; &mdash; static redirect</text> + + <path d="M150,130 L150,160" class="arrow"/> + <rect x="30" y="160" width="240" height="50" rx="10" class="node"/> + <text x="150" y="180" text-anchor="middle" class="node-text">vercel.json redirect rule</text> + <text x="150" y="195" text-anchor="middle" class="node-text" font-size="10">instant, no function cold-start</text> + + <rect x="410" y="90" width="240" height="40" rx="10" class="node"/> + <text x="530" y="115" text-anchor="middle" class="node-text">/api/file/&lt;item_id&gt;</text> + + <path d="M530,130 L530,160" class="arrow"/> + <rect x="410" y="160" width="240" height="60" rx="10" class="node"/> + <text x="530" y="180" text-anchor="middle" class="node-text">Backend checks item.meta.json</text> + <text x="530" y="196" text-anchor="middle" class="node-text" font-size="10">expired? &rarr; HTTP 410</text> + <text x="530" y="210" text-anchor="middle" class="node-text" font-size="10">valid? &rarr; 302 redirect to HF</text> + + <path d="M150,210 L150,230 L340,230" class="arrow"/> + <path d="M530,220 L530,230 L340,230" class="arrow"/> + <rect x="240" y="230" width="200" height="30" rx="8" class="node-alt"/> + <text x="340" y="250" text-anchor="middle" class="node-text-alt">File served from Hugging Face</text> + </svg> + </div> + <ul class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark list-disc pl-5 space-y-1"> + <li><strong>Permanent links</strong> are handled entirely by Vercel's static redirect rules &mdash; the Python function never even runs, so they're as fast as a link can be.</li> + <li><strong>Expiring links</strong> must go through the backend on every open, since something has to check "has this passed its expiry time yet?" before deciding where to send you.</li> + <li>Nothing is ever deleted. An expired link just stops redirecting &mdash; the file stays in the dataset.</li> + </ul> + </section> + + <!-- ===================== Section: Upload via URL ===================== --> + <section class="mb-14"> + <h2 class="text-xl font-bold mb-3">4. Uploading from a URL</h2> + <p class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark mb-4"> + Instead of uploading from your device, you can hand the tool a link and have the server fetch + and re-host it &mdash; useful for re-hosting an image or file that's only temporarily available elsewhere. + </p> + <div class="diagram-box rounded-[20px] p-4 overflow-x-auto"> + <svg viewBox="0 0 680 100" xmlns="http://www.w3.org/2000/svg" class="min-w-[600px]"> + <rect x="10" y="30" width="150" height="40" rx="10" class="node-alt"/> + <text x="85" y="55" text-anchor="middle" class="node-text-alt">You paste a URL</text> + + <path d="M160,50 L250,50" class="arrow"/> + <rect x="250" y="30" width="180" height="40" rx="10" class="node"/> + <text x="340" y="55" text-anchor="middle" class="node-text">Backend fetches the URL</text> + + <path d="M430,50 L520,50" class="arrow"/> + <rect x="520" y="30" width="150" height="40" rx="10" class="node-alt"/> + <text x="595" y="55" text-anchor="middle" class="node-text-alt">Uploaded to HF, same as normal</text> + </svg> + </div> + <p class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark mt-3"> + Same 4.4&nbsp;MB size limit applies to the fetched file, and it supports the same custom ID and expiry options. + </p> + </section> + + <!-- ===================== Section: Batch links ===================== --> + <section class="mb-14"> + <h2 class="text-xl font-bold mb-3">5. Batch links</h2> + <p class="text-sm leading-relaxed text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark mb-4"> + Upload more than one file at once and, alongside each file's own link, you also get a single + shareable <code>/batch/&lt;id&gt;</code> link that opens a page listing every file from that batch. + </p> + <div class="diagram-box rounded-[20px] p-4 overflow-x-auto"> + <svg viewBox="0 0 680 180" xmlns="http://www.w3.org/2000/svg" class="min-w-[600px]"> + <rect x="20" y="20" width="200" height="40" rx="10" class="node-alt"/> + <text x="120" y="45" text-anchor="middle" class="node-text-alt">Upload 3+ files together</text> + + <path d="M120,60 L120,90" class="arrow"/> + <rect x="20" y="90" width="200" height="50" rx="10" class="node"/> + <text x="120" y="110" text-anchor="middle" class="node-text">Each file uploaded normally</text> + <text x="120" y="125" text-anchor="middle" class="node-text" font-size="10">gets its own item_id</text> + + <path d="M220,115 L340,115" class="arrow"/> + <rect x="340" y="90" width="200" height="50" rx="10" class="node"/> + <text x="440" y="110" text-anchor="middle" class="node-text">Manifest written</text> + <text x="440" y="125" text-anchor="middle" class="node-text" font-size="10">_batches/&lt;batch_id&gt;.json</text> + + <path d="M540,115 L620,115 L620,150" class="arrow"/> + <rect x="510" y="150" width="150" height="30" rx="8" class="node-alt"/> + <text x="585" y="170" text-anchor="middle" class="node-text-alt" font-size="10">/batch/&lt;id&gt; page</text> + </svg> + </div> + </section> + + <!-- ===================== Section: Limits table ===================== --> + <section class="mb-14"> + <h2 class="text-xl font-bold mb-3">6. Limits &amp; behavior at a glance</h2> + <div class="bg-m3-surfaceContainer dark:bg-m3-surfaceContainerDark rounded-[16px] overflow-hidden text-sm"> + <table class="w-full border-collapse"> + <tbody> + <tr class="border-b border-m3-surfaceContainerHighest dark:border-m3-surfaceContainerHighestDark"> + <td class="px-4 py-3 font-semibold w-1/2">Max file size</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">~4.4&nbsp;MB per file (Vercel request-body limit)</td> + </tr> + <tr class="border-b border-m3-surfaceContainerHighest dark:border-m3-surfaceContainerHighestDark"> + <td class="px-4 py-3 font-semibold">File types</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">Any extension, unrestricted</td> + </tr> + <tr class="border-b border-m3-surfaceContainerHighest dark:border-m3-surfaceContainerHighestDark"> + <td class="px-4 py-3 font-semibold">Multiple files</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">Supported; each gets its own link + one shared batch link</td> + </tr> + <tr class="border-b border-m3-surfaceContainerHighest dark:border-m3-surfaceContainerHighestDark"> + <td class="px-4 py-3 font-semibold">Custom ID</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">Single-file uploads only, sanitized to letters/numbers/dot/dash/underscore</td> + </tr> + <tr class="border-b border-m3-surfaceContainerHighest dark:border-m3-surfaceContainerHighestDark"> + <td class="px-4 py-3 font-semibold">Expiry</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">Optional: 1h / 1d / 7d / 30d / never. Disables the link only &mdash; the file itself is never deleted</td> + </tr> + <tr class="border-b border-m3-surfaceContainerHighest dark:border-m3-surfaceContainerHighestDark"> + <td class="px-4 py-3 font-semibold">Deletion</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">Not supported by design</td> + </tr> + <tr class="border-b border-m3-surfaceContainerHighest dark:border-m3-surfaceContainerHighestDark"> + <td class="px-4 py-3 font-semibold">Authentication</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">None &mdash; the tool is intentionally open</td> + </tr> + <tr> + <td class="px-4 py-3 font-semibold">Storage</td> + <td class="px-4 py-3 text-m3-onSurfaceVariant dark:text-m3-onSurfaceVariantDark">Public Hugging Face dataset repo</td> + </tr> + </tbody> + </table> + </div> + </section> + + <a href="/" class="inline-flex items-center gap-1 text-sm font-semibold text-m3-primary dark:text-m3-primaryDark"> + <span class="material-symbols-outlined text-[18px]">arrow_back</span> Back to Upload + </a> + +</div> + +</body> +</html>
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror