Skip to content

Commit

Permalink
initTime remove
Browse files Browse the repository at this point in the history
  • Loading branch information
matvp91 committed Nov 14, 2024
1 parent 0af1ac9 commit 0a3655d
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 35 deletions.
13 changes: 9 additions & 4 deletions packages/stitcher/src/interstitials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DateTime } from "luxon";
import { assert } from "shared/assert";
import { env } from "./env";
import { resolveUri, toAssetProtocol } from "./lib/url";
import { fetchMasterPlaylistDuration } from "./playlist";
Expand All @@ -22,18 +23,20 @@ interface InterstitialAsset {
}

export function getStaticDateRanges(session: Session) {
assert(session.startTime, "No startTime in session");

const group: Record<string, InterstitialType[]> = {};

if (session.vmapResponse) {
for (const adBreak of session.vmapResponse.adBreaks) {
const dateTime = session.initTime.plus({ seconds: adBreak.timeOffset });
const dateTime = session.startTime.plus({ seconds: adBreak.timeOffset });
groupTimeOffset(group, dateTime, "ad");
}
}

if (session.interstitials) {
for (const interstitial of session.interstitials) {
const dateTime = session.initTime.plus({
const dateTime = session.startTime.plus({
seconds: interstitial.timeOffset,
});
groupTimeOffset(group, dateTime, interstitial.type);
Expand Down Expand Up @@ -80,13 +83,15 @@ function groupTimeOffset(
}

export async function getAssets(session: Session, lookupDate: DateTime) {
assert(session.startTime, "No startTime in session");

const assets: InterstitialAsset[] = [];

if (session.vmapResponse) {
await formatStaticAdBreaks(
assets,
session.vmapResponse,
session.initTime,
session.startTime,
lookupDate,
);
}
Expand All @@ -95,7 +100,7 @@ export async function getAssets(session: Session, lookupDate: DateTime) {
await formatStaticInterstitials(
assets,
session.interstitials,
session.initTime,
session.startTime,
lookupDate,
);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/stitcher/src/lib/url.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as path from "path";
import { env } from "../env";
import type { Filter } from "../filters";
import type { Session } from "../session";

const uuidRegex = /^[a-z,0-9,-]{36,36}$/;

Expand Down Expand Up @@ -69,13 +70,13 @@ export function buildProxyUrl(
url: string,
params?: {
filter?: Filter;
sessionId?: string;
session?: Session;
params?: Record<string, string>;
},
) {
return buildUrl(`${env.PUBLIC_STITCHER_ENDPOINT}/out/${file}`, {
url,
sessionId: params?.sessionId,
sid: params?.session?.id,

// Filter query params.
"filter.resolution": params?.filter?.resolution,
Expand Down
10 changes: 7 additions & 3 deletions packages/stitcher/src/playlist.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DateTime } from "luxon";
import { assert } from "shared/assert";
import { filterMasterPlaylist } from "./filters";
import { getAssets, getStaticDateRanges } from "./interstitials";
import { buildProxyUrl, joinUrl, resolveUri } from "./lib/url";
Expand All @@ -23,7 +24,7 @@ export async function formatMasterPlaylist(

for (const variant of master.variants) {
variant.uri = buildProxyUrl("playlist.m3u8", joinUrl(url, variant.uri), {
sessionId: session.id,
session,
params: {
type: "video",
},
Expand All @@ -46,7 +47,7 @@ export async function formatMasterPlaylist(
"playlist.m3u8",
joinUrl(url, rendition.uri),
{
sessionId: session.id,
session,
params: {
type,
},
Expand All @@ -62,12 +63,15 @@ export async function formatMediaPlaylist(
type: "video" | "audio" | "text",
url: string,
) {
assert(session.startTime, "No startTime in session");

const media = await fetchMediaPlaylist(url);

if (type === "video" && media.endlist && media.segments[0]) {
// When we have an endlist, the playlist is static. We can check whether we need
// to add dateRanges.
media.segments[0].programDateTime = session.initTime;

media.segments[0].programDateTime = session.startTime;
media.dateRanges = getStaticDateRanges(session);
}

Expand Down
14 changes: 7 additions & 7 deletions packages/stitcher/src/routes/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export const session = new Elysia()
.post(
"/session",
async ({ body }) => {
const sessionId = await createSession(body);
const session = await createSession(body);

const masterUrl = resolveUri(body.uri);

const url = buildProxyUrl("master.m3u8", masterUrl, {
sessionId,
session,
filter: body.filter,
});

Expand Down Expand Up @@ -87,9 +87,9 @@ export const session = new Elysia()
.get(
"/out/master.m3u8",
async ({ set, query }) => {
const session = await getSession(query.sessionId);
const session = await getSession(query.sid);

await formatSessionByMasterRequest(query.sessionId, session);
await formatSessionByMasterRequest(session);

const filter = extractFilterFromQuery(query);

Expand All @@ -105,15 +105,15 @@ export const session = new Elysia()
},
query: t.Object({
url: t.String(),
sessionId: t.String(),
sid: t.String(),
"filter.resolution": t.Optional(t.String()),
}),
},
)
.get(
"/out/playlist.m3u8",
async ({ set, query }) => {
const session = await getSession(query.sessionId);
const session = await getSession(query.sid);

const playlist = await formatMediaPlaylist(
session,
Expand All @@ -136,7 +136,7 @@ export const session = new Elysia()
t.Literal("text"),
]),
url: t.String(),
sessionId: t.String(),
sid: t.String(),
}),
},
)
Expand Down
43 changes: 24 additions & 19 deletions packages/stitcher/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type { VmapResponse } from "./vmap";

export interface Session {
id: string;
initTime: DateTime;
startTime?: DateTime;
expiry: number;
vmap?: {
url: string;
};
Expand All @@ -25,14 +26,15 @@ export async function createSession(params: {
uri: string;
type?: InterstitialType;
}[];
expiry?: number;
}) {
const id = randomUUID();

const initTime = DateTime.now();
const session: Session = {
id,
initTime,
vmap: params.vmap,
// A session is valid for 3 hours by default.
expiry: params.expiry ?? 60 * 60 * 3,
};

if (params.interstitials?.length) {
Expand All @@ -45,10 +47,11 @@ export async function createSession(params: {
});
}

const ttl = 3600;
await kv.set(`session:${id}`, serializeSession(session), ttl);
// We'll initially store the session for 10 minutes, if it's not been consumed
// within the timeframe, it's gone.
await kv.set(`session:${id}`, serializeSession(session), 60 * 10);

return id;
return session;
}

export async function getSession(id: string) {
Expand All @@ -59,30 +62,32 @@ export async function getSession(id: string) {
return deserializeSession(id, data);
}

export async function formatSessionByMasterRequest(
id: string,
session: Session,
) {
let updateSession = false;
export async function formatSessionByMasterRequest(session: Session) {
// Check if we have a startTime, if so, the master playlist has been requested
// before and we no longer need it.
if (session.startTime) {
return;
}

session.startTime = DateTime.now();

if (session.vmap) {
session.vmapResponse = await fetchVmap(session.vmap.url);
delete session.vmap;

updateSession = true;
}

if (updateSession) {
const ttl = 3600;
await kv.set(`session:${id}`, serializeSession(session), ttl);
}
await kv.set(
`session:${session.id}`,
serializeSession(session),
session.expiry,
);
}

function serializeSession(session: Session) {
const copy = {
...session,
id: undefined,
initTime: session.initTime.toISO(),
startTime: session.startTime?.toISO(),
};
return JSON.stringify(copy);
}
Expand All @@ -92,7 +97,7 @@ function deserializeSession(id: string, value: string): Session {
const session = {
...copy,
id,
initTime: DateTime.fromISO(copy.initTime),
startTime: copy.startTime ? DateTime.fromISO(copy.startTime) : undefined,
};
return session;
}

0 comments on commit 0a3655d

Please sign in to comment.