music video renderer web app deftoku.digi.rip
audio visualizer webapp
1

Configure Feed

Select the types of activity you want to include in your feed.

deno, dev_server: replace dev task with custom dev server w/ live reload

digi.rip (Jun 19, 2026, 11:32 PM EDT) 4061adc0 fa6576f1

+181 -1
+2 -1
deno.json
··· 4 4 }, 5 5 "nodeModulesDir": "manual", 6 6 "tasks": { 7 - "dev": "deno task build && deno run -A jsr:@std/http/file-server", 7 + "dev": "deno run -A dev_server.ts", 8 8 "build": "deno run -A npm:esbuild --bundle src/mod.ts --outfile=dist/dist.js --format=esm" 9 9 }, 10 10 "imports": { 11 + "@std/http": "jsr:@std/http@^1", 11 12 "mediabunny": "npm:mediabunny@^1.49.0" 12 13 } 13 14 }
+62
deno.lock
··· 1 1 { 2 2 "version": "5", 3 3 "specifiers": { 4 + "jsr:@std/cli@^1.0.30": "1.0.30", 5 + "jsr:@std/encoding@^1.0.10": "1.0.10", 6 + "jsr:@std/fmt@^1.0.10": "1.0.10", 7 + "jsr:@std/fs@^1.0.24": "1.0.24", 8 + "jsr:@std/html@^1.0.7": "1.0.7", 9 + "jsr:@std/http@*": "1.1.1", 10 + "jsr:@std/http@1": "1.1.1", 11 + "jsr:@std/internal@^1.0.14": "1.0.14", 12 + "jsr:@std/media-types@^1.1.0": "1.1.0", 13 + "jsr:@std/net@^1.0.6": "1.0.6", 14 + "jsr:@std/path@^1.1.5": "1.1.5", 15 + "jsr:@std/streams@^1.1.1": "1.1.1", 4 16 "npm:mediabunny@^1.49.0": "1.49.0" 5 17 }, 18 + "jsr": { 19 + "@std/cli@1.0.30": { 20 + "integrity": "769446536522d0417d7127ebcabcafac1ab0ce6766d0eb3fca1d36326fe98d13" 21 + }, 22 + "@std/encoding@1.0.10": { 23 + "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" 24 + }, 25 + "@std/fmt@1.0.10": { 26 + "integrity": "90dfba288802ac6de82fb31d0917eb9e4450b9925b954d5e51fc29ac07419db5" 27 + }, 28 + "@std/fs@1.0.24": { 29 + "integrity": "f3061b45b81673a2bece689da041df32d174be064c89eb6397fb5718d3fb7877" 30 + }, 31 + "@std/html@1.0.7": { 32 + "integrity": "175c818905a6e75743c69c251395e273d82698e58cfe7dd76268d70e28b8d8fe" 33 + }, 34 + "@std/http@1.1.1": { 35 + "integrity": "e343a9a80aea07c716b91be5c79df764144430ad2dd7c9121ed7443f08dc74f7", 36 + "dependencies": [ 37 + "jsr:@std/cli", 38 + "jsr:@std/encoding", 39 + "jsr:@std/fmt", 40 + "jsr:@std/fs", 41 + "jsr:@std/html", 42 + "jsr:@std/media-types", 43 + "jsr:@std/net", 44 + "jsr:@std/path", 45 + "jsr:@std/streams" 46 + ] 47 + }, 48 + "@std/internal@1.0.14": { 49 + "integrity": "291516b3d4c35024d6ffbc0a9df5bf4c64116e05b50012cf846710152d2ffdf7" 50 + }, 51 + "@std/media-types@1.1.0": { 52 + "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" 53 + }, 54 + "@std/net@1.0.6": { 55 + "integrity": "110735f93e95bb9feb95790a8b1d1bf69ec0dc74f3f97a00a76ea5efea25500c" 56 + }, 57 + "@std/path@1.1.5": { 58 + "integrity": "ccea00982ea28c36becaf6e62f855406c76a8c32d462f66f415bbb7d83a271bc", 59 + "dependencies": [ 60 + "jsr:@std/internal" 61 + ] 62 + }, 63 + "@std/streams@1.1.1": { 64 + "integrity": "92556d350e537e9dce527a6d08f6f15be3ff65e656079dea69d15252187c7613" 65 + } 66 + }, 6 67 "npm": { 7 68 "@types/dom-mediacapture-transform@0.1.11": { 8 69 "integrity": "sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==", ··· 23 84 }, 24 85 "workspace": { 25 86 "dependencies": [ 87 + "jsr:@std/http@1", 26 88 "npm:mediabunny@^1.49.0" 27 89 ] 28 90 }
+117
dev_server.ts
··· 1 + import { serveDir } from "@std/http/file-server"; 2 + 3 + const RELOAD_PATH = "/__reload"; 4 + const RELOAD_SCRIPT = 5 + `<script>new EventSource("${RELOAD_PATH}").addEventListener("reload",()=>location.reload())</script>`; 6 + const DIST_FILE = "dist/dist.js"; 7 + 8 + const clients = new Set<ReadableStreamDefaultController>(); 9 + 10 + function broadcast(event: string, data = "") { 11 + const msg = new TextEncoder().encode(`event: ${event}\ndata: ${data}\n\n`); 12 + for (const c of clients) { 13 + try { 14 + c.enqueue(msg); 15 + } catch { 16 + clients.delete(c); 17 + } 18 + } 19 + } 20 + 21 + function sseHandler(req: Request): Response { 22 + const stream = new ReadableStream({ 23 + start(controller) { 24 + clients.add(controller); 25 + req.signal.addEventListener("abort", () => clients.delete(controller)); 26 + }, 27 + }); 28 + return new Response(stream, { 29 + headers: { 30 + "content-type": "text/event-stream", 31 + "cache-control": "no-cache", 32 + }, 33 + }); 34 + } 35 + 36 + const handler = async (req: Request): Promise<Response> => { 37 + const url = new URL(req.url); 38 + 39 + // SSE endpoint for live reload 40 + if (url.pathname === RELOAD_PATH) return sseHandler(req); 41 + 42 + // serve static files 43 + const res = await serveDir(req, { fsRoot: Deno.cwd() }); 44 + 45 + // inject live-reload script into HTML responses 46 + if (res.headers.get("content-type")?.includes("text/html")) { 47 + const body = await res.text(); 48 + const headers = new Headers(res.headers); 49 + headers.set("content-type", "text/html; charset=utf-8"); 50 + headers.delete("content-length"); 51 + return new Response(body.replace("</body>", RELOAD_SCRIPT + "</body>"), { 52 + status: res.status, 53 + headers, 54 + }); 55 + } 56 + 57 + return res; 58 + }; 59 + 60 + let reloadTimer: number | undefined; 61 + 62 + async function startWatcher() { 63 + try { 64 + const watcher = Deno.watchFs(DIST_FILE); 65 + for await (const event of watcher) { 66 + if (event.kind === "modify" || event.kind === "create") { 67 + clearTimeout(reloadTimer); 68 + reloadTimer = setTimeout(() => broadcast("reload"), 80); 69 + } 70 + } 71 + } catch (err) { 72 + console.error("Watcher error:", err); 73 + } 74 + } 75 + 76 + function startBuildWatch() { 77 + const cmd = new Deno.Command("deno", { 78 + args: [ 79 + "run", 80 + "-A", 81 + "npm:esbuild", 82 + "--bundle", 83 + "src/mod.ts", 84 + `--outfile=${DIST_FILE}`, 85 + "--format=esm", 86 + "--watch=forever", 87 + ], 88 + stdout: "inherit", 89 + stderr: "inherit", 90 + }); 91 + 92 + const proc = cmd.spawn(); 93 + 94 + // clean up on exit 95 + globalThis.addEventListener("unload", () => { 96 + proc.kill(); 97 + }); 98 + 99 + proc.status.then((status) => { 100 + if (!status.success) { 101 + console.error("esbuild exited with code", status.code); 102 + } 103 + }); 104 + 105 + return proc; 106 + } 107 + 108 + console.log(""); 109 + console.log(" ╔═══════════════════════════════╗"); 110 + console.log(" ║ deftoku dev server ║"); 111 + console.log(" ║ http://localhost:8000 ║"); 112 + console.log(" ╚═══════════════════════════════╝"); 113 + console.log(""); 114 + 115 + startBuildWatch(); 116 + startWatcher(); 117 + Deno.serve({ port: 8000, onListen: () => {} }, handler);