Frame-by-frame dag/natt-filmer, väderlager (Open-Meteo), vind, måne, norrsken (NOAA Kp), fyra informationsrutor med karta och platsval. Cloudflare Worker med Range-stöd för video. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
25 lines
1.2 KiB
JavaScript
25 lines
1.2 KiB
JavaScript
// Static assets + HTTP Range for /video/* (Safari/iOS will not play video without 206 responses)
|
|
export default {
|
|
async fetch(req, env) {
|
|
const url = new URL(req.url);
|
|
const range = req.headers.get('Range');
|
|
if (!url.pathname.startsWith('/video/') || !range) return env.ASSETS.fetch(req);
|
|
|
|
const full = await env.ASSETS.fetch(new Request(url, { method: 'GET' }));
|
|
if (!full.ok) return full;
|
|
const buf = await full.arrayBuffer(), size = buf.byteLength;
|
|
const m = /^bytes=(\d*)-(\d*)$/.exec(range.trim());
|
|
let start, end;
|
|
if (m && m[1] !== '') { start = +m[1]; end = m[2] !== '' ? Math.min(+m[2], size - 1) : size - 1; }
|
|
else if (m && m[2] !== '') { start = Math.max(0, size - +m[2]); end = size - 1; }
|
|
if (!m || start > end || start >= size)
|
|
return new Response(null, { status: 416, headers: { 'Content-Range': `bytes */${size}` } });
|
|
|
|
const h = new Headers(full.headers);
|
|
h.set('Content-Range', `bytes ${start}-${end}/${size}`);
|
|
h.set('Content-Length', String(end - start + 1));
|
|
h.set('Accept-Ranges', 'bytes');
|
|
return new Response(req.method === 'HEAD' ? null : buf.slice(start, end + 1), { status: 206, headers: h });
|
|
},
|
|
};
|