ybabts
ybabts
DDeno
Created by ybabts on 7/27/2023 in #help
HTTP 206 + HTML5 video streaming with Fresh
how do I implement an endpoint to stream a video to a HTML video player using HTTP 206 in Fresh? Here's what I have so far however it doesn't seem to be working.
import { HandlerContext } from "$fresh/server.ts";
import { Err, isErr, Ok } from "eav/mod.ts";

const video = await Deno.readFile("./static/assets/hero.mp4");

const chunkSize = 1024 * 1024 * 10;

export async function handler(
req: Request,
ctx: HandlerContext,
): Promise<Response> {
if (req.headers.has("range")) {
const range = Ok(parseRange(req.headers.get("range")!)) ??
{ start: 0, end: NaN };
if (range.start === 0 && isNaN(range.end)) {
return new Response(video.slice(0, chunkSize), {
status: 206,
headers: {
"Content-Type": "video/mp4",
"Content-Length": chunkSize.toString(),
"Content-Range": `bytes 0-100/${video.length}`,
"Accept-Ranges": "bytes",
},
});
}
const end = isNaN(range.end) ? range.start + chunkSize : range.end;
return new Response(video.slice(range.start, end), {
status: 206,
headers: {
"Content-Type": "video/mp4",
"Content-Length": chunkSize.toString(),
"Content-Range": `bytes ${range.start}-${end}/${video.length}`,
"Accept-Ranges": "bytes",
},
});
}
return new Response(null, {
status: 404,
});
}

function parseRange(range: string) {
if (!range.includes("bytes=")) {
return new Err("invalid range");
}
const [_, rangeStr] = range.split("=");
const [start, end] = rangeStr.split("-");
return { start: parseInt(start), end: parseInt(end) };
}
import { HandlerContext } from "$fresh/server.ts";
import { Err, isErr, Ok } from "eav/mod.ts";

const video = await Deno.readFile("./static/assets/hero.mp4");

const chunkSize = 1024 * 1024 * 10;

export async function handler(
req: Request,
ctx: HandlerContext,
): Promise<Response> {
if (req.headers.has("range")) {
const range = Ok(parseRange(req.headers.get("range")!)) ??
{ start: 0, end: NaN };
if (range.start === 0 && isNaN(range.end)) {
return new Response(video.slice(0, chunkSize), {
status: 206,
headers: {
"Content-Type": "video/mp4",
"Content-Length": chunkSize.toString(),
"Content-Range": `bytes 0-100/${video.length}`,
"Accept-Ranges": "bytes",
},
});
}
const end = isNaN(range.end) ? range.start + chunkSize : range.end;
return new Response(video.slice(range.start, end), {
status: 206,
headers: {
"Content-Type": "video/mp4",
"Content-Length": chunkSize.toString(),
"Content-Range": `bytes ${range.start}-${end}/${video.length}`,
"Accept-Ranges": "bytes",
},
});
}
return new Response(null, {
status: 404,
});
}

function parseRange(range: string) {
if (!range.includes("bytes=")) {
return new Err("invalid range");
}
const [_, rangeStr] = range.split("=");
const [start, end] = rangeStr.split("-");
return { start: parseInt(start), end: parseInt(end) };
}
I would bash my head against this some more but I'm going to sleep so I figure if someone knows it'll be useful. I plan on making a middleware to automatically stream any content that is over a certain size.
1 replies
DDeno
Created by ybabts on 7/12/2023 in #help
DNS Records and Deno
so I am confused I'm building an application that uses Steam's web API and am looking at why the response times are taking so long and with the perf headers I have in my application I can see it takes a while to make the requests (260-300 ms) so I investigated where Steam's API servers are located and found that there is one in Los Angeles so I spun up an EC2 instance there and pinged the domain name api.steampowered.com and the latency was still ~260 ms I used some online tools to find out that it's resolving the domain name to an IP that's located in Minnesota so I found the one for Los Angeles and the latency was ~0.5-5 ms which sounds correct, but using the api.steampowered.com domain still resolves to the wrong IP so I tried editing /etc/hosts and adding in the host myself to make it resolve to that IP address but based on the latency of the request it's still resolving to the Minnesota IP so I tried changing the IP to something other than a Steam API server to make sure that the manual DNS record was working and it is working, but it's also not working? doing ping on api.steampowered.com with the manually set DNS record works as expected, resulting in very low latency but doing fetch in Deno seems to resolve to a different IP address than what ping resolves to I can't just replace api.steampowered.com with the IP (104.90.122.79) either because the server responds with a 400 Bad Request "Invalid URL" if I replace the domain name with an IP I've also made sure to restart the systemd-resolved service after changing /etc/hosts
2 replies
DDeno
Created by ybabts on 7/7/2023 in #help
Typescript Conditional Type Returns
I don't know why but this conditional type return is just causing me grief.
type InnerType<T> = T extends Promise<infer U> ? U : never;

export function CaptureErr<
F extends (...args: any[]) => any,
N extends string,
R extends ReturnType<F>,
>(
name: N,
fn: F,
message?: string,
): R extends Promise<any> ? Promise<InnerType<R> | Err<N>> : R | Err<N> {
try {
const result = fn();
if (result instanceof Promise) {
// Type 'Promise<Err<N> | InnerType<R>>' is not assignable to type
// 'R extends Promise<any> ? Promise<InnerType<R> | Err<N>> : R | Err<N>'.
return result.catch((e: Error) => {
e.cause = new Err(name ?? e.name, message ?? e.message);
return Promise.resolve(e as Err<N>);
}) as Promise<InnerType<R> | Err<N>>;
}
return result;
} catch (error) {
error.cause = new Err(name ?? error.name, message ?? error.message);
return error;
}
}
type InnerType<T> = T extends Promise<infer U> ? U : never;

export function CaptureErr<
F extends (...args: any[]) => any,
N extends string,
R extends ReturnType<F>,
>(
name: N,
fn: F,
message?: string,
): R extends Promise<any> ? Promise<InnerType<R> | Err<N>> : R | Err<N> {
try {
const result = fn();
if (result instanceof Promise) {
// Type 'Promise<Err<N> | InnerType<R>>' is not assignable to type
// 'R extends Promise<any> ? Promise<InnerType<R> | Err<N>> : R | Err<N>'.
return result.catch((e: Error) => {
e.cause = new Err(name ?? e.name, message ?? e.message);
return Promise.resolve(e as Err<N>);
}) as Promise<InnerType<R> | Err<N>>;
}
return result;
} catch (error) {
error.cause = new Err(name ?? error.name, message ?? error.message);
return error;
}
}
2 replies
DDeno
Created by ybabts on 7/7/2023 in #help
Parsing Hostname for TLD, domain name, and SLD
does anyone know of any packages to parse a URL's hostname for the top level domain, domain name, and sublevel domains? I found one, but it actually just doesn't work. It just errors saying the label is too short for everything I give it. https://github.com/lupomontero/psl
9 replies
DDeno
Created by ybabts on 10/25/2022 in #help
Deno NPM VSCode Intellisense
Is there a work around for this at the moment? I want to try out Deno's NPM support but I lose Intellisense when importing with npm:. I tried using an import map but that didn't work either. If there's a code editor or an IDE that currently supports this feature I would love to know.
10 replies