cdn

Log | Files | Refs | Activity

commit a54bbe96ac476ed4e2dfcce65076a1a658598dcb
parent a9369939a62e73fe3b9579a14f3190f090b911ba
Author: Amit Dutta <mail@amit.is-a.dev>
Date:   Thu,  3 Sep 2026 19:14:48 +0530

Merge pull request #7 from notamitgamer/patch

Implement in-memory caching for file checks and listings
Diffstat:
Mapp/main.py | 8++++++++
Mapp/storage.py | 37++++++++++++++++++++++++++++++++++---
Mapp/templates/index.html | 37++++++++++++++++++++++++++++---------
3 files changed, 70 insertions(+), 12 deletions(-)

diff --git a/app/main.py b/app/main.py @@ -19,6 +19,14 @@ RAW_DOMAIN = os.getenv("RAW_DOMAIN", "raw.cdn.amit.is-a.dev") RAW_BASE_URL = os.getenv("RAW_BASE_URL", f"https://{RAW_DOMAIN}") RAW_PREFIX = "raw/" +@app.exception_handler(404) +async def not_found_handler(request: Request, exc: HTTPException): + # Keep the raw subdomain returning plain text errors + if request.url.hostname == RAW_DOMAIN: + return PlainTextResponse("404: File Not Found", status_code=404) + # Render UI 404 page for the main CDN domain + return templates.TemplateResponse(request, "index.html", {"page": "404"}, status_code=404) + async def stream_raw(path: str): hf_url = f"https://huggingface.co/datasets/{HF_REPO_ID}/resolve/main/{path}" client = httpx.AsyncClient(follow_redirects=True) diff --git a/app/storage.py b/app/storage.py @@ -1,4 +1,5 @@ import os +import time import uuid import httpx from huggingface_hub import HfApi @@ -9,17 +10,43 @@ HF_TOKEN = os.getenv("HF_TOKEN") api = HfApi(token=HF_TOKEN) +# --- SPEED OPTIMIZATION: IN-MEMORY CACHE --- +_cache = {} +CACHE_TTL = 60 # Cache folder layouts for 60 seconds to make navigation instant + +def _get_cache(key): + if key in _cache and _cache[key][0] > time.time(): + return _cache[key][1] + return None + +def _set_cache(key, value): + _cache[key] = (time.time() + CACHE_TTL, value) +# ------------------------------------------- + async def is_file(path: str) -> bool: """Check if a path in the HF dataset is a file using a quick HEAD request.""" if not path: return False + + cache_key = f"is_file_{path}" + cached = _get_cache(cache_key) + if cached is not None: + return cached + hf_url = f"https://huggingface.co/datasets/{HF_REPO_ID}/resolve/main/{path}" async with httpx.AsyncClient() as client: r = await client.head(hf_url) - return r.status_code == 200 + result = r.status_code == 200 + _set_cache(cache_key, result) + return result def list_directory(path: str): """Returns list of dicts for items in directory, sorted folders first.""" + cache_key = f"list_dir_{path}" + cached = _get_cache(cache_key) + if cached is not None: + return cached + try: items = list(api.list_repo_tree(repo_id=HF_REPO_ID, path_in_repo=path, repo_type="dataset")) except Exception: @@ -48,6 +75,8 @@ def list_directory(path: str): }) files_and_folders.sort(key=lambda x: (not x["is_dir"], x["name"].lower())) + + _set_cache(cache_key, files_and_folders) return files_and_folders def upload_temp_file(temp_path: str, filename: str) -> str: @@ -63,4 +92,7 @@ def upload_temp_file(temp_path: str, filename: str) -> str: repo_type="dataset", token=HF_TOKEN ) - return hf_path- \ No newline at end of file + + # Clear cache so the newly uploaded file is immediately visible in directories + _cache.clear() + return hf_path diff --git a/app/templates/index.html b/app/templates/index.html @@ -4,10 +4,14 @@ <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CDN | {{ page | capitalize }}</title> + + <!-- ADD THIS: Turbo to make the site a Single Page App --> + <script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.4/dist/turbo.es2017-esm.js"></script> + <style> :root { - --bg: #0d1117; - --surface: #161b22; + --bg: #050505; + --surface: #121212; --text-main: #c9d1d9; --text-dim: #8b949e; --accent-pink: #ffb4ab; @@ -25,7 +29,7 @@ margin: 0; padding: 3rem 1.5rem; line-height: 1.6; - font-size: 0.9rem; + font-size: 1rem; } .container { @@ -177,6 +181,12 @@ .file-row.done { border-color: #2ea043; } .file-row.error { border-color: var(--danger); } + /* ADD THIS: Style the Turbo progress bar to match your theme */ + .turbo-progress-bar { + height: 3px; + background-color: var(--accent-pink); + } + footer { margin-top: 4rem; padding-top: 1rem; @@ -247,14 +257,15 @@ <a href="/{{ item.path }}">{{ item.name }}/</a> {% else %} <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg> - <!-- Updated to link directly to the new raw subdomain --> - <a href="{{ raw_base_url }}/{{ item.path }}">{{ item.name }}</a> + <!-- ADD data-turbo="false" so clicking raw files doesn't trigger the SPA router --> + <a href="{{ raw_base_url }}/{{ item.path }}" data-turbo="false">{{ item.name }}</a> {% endif %} </div> <div class="item-meta"> {% if not item.is_dir %} <span>{{ item.size_str }}</span> - <a href="/api/download/{{ item.path }}" class="download-icon" title="Download"> + <!-- ADD data-turbo="false" to download links --> + <a href="/api/download/{{ item.path }}" class="download-icon" title="Download" data-turbo="false"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15V3"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/></svg> </a> {% endif %} @@ -293,14 +304,22 @@ <p style="color: var(--text-dim); margin-bottom: 2rem; font-size: 0.85rem; word-break: break-all;">{{ path }}</p> <div style="display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap;"> - <a href="/api/download/{{ path }}" class="btn">Download</a> - <!-- Updated links to utilize raw_base_url --> - <a href="{{ raw_base_url }}/{{ path }}" class="btn">Open Raw</a> + <!-- ADD data-turbo="false" to these action buttons --> + <a href="/api/download/{{ path }}" class="btn" data-turbo="false">Download</a> + <a href="{{ raw_base_url }}/{{ path }}" class="btn" data-turbo="false">Open Raw</a> <button onclick="copyToClipboard(window.location.origin + '/' + '{{ path }}')" class="btn">Copy Link</button> <button onclick="copyToClipboard('{{ raw_base_url }}/{{ path }}')" class="btn">Copy Raw Link</button> </div> </div> + {% elif page == '404' %} + <div class="list-container" style="padding: 4rem 1.5rem; text-align: center;"> + <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="var(--danger)" stroke-width="1.5" style="margin-bottom: 1rem;"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> + <h2 style="margin: 0 0 0.5rem 0; font-weight: normal; color: var(--danger);">404 - Not Found</h2> + <p style="color: var(--text-dim); margin-bottom: 2rem;">The file or directory you're looking for doesn't exist.</p> + <a href="/" class="btn">Go to Root</a> + </div> + {% elif page == 'upload' %} <blockquote> If you do not remember the link, go to the <a href="/uploads">uploads folder</a> to find your file.
© notamitgamer • Site Built: 2026-09-05 01:53:16 UTC • git-mirror commit: c170d72 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror