-
-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Stitcher support abs url (#112)
* Added support for absolute URLS * initTime remove * Encrypt url * Added audioLanguage filter
- Loading branch information
Showing
32 changed files
with
461 additions
and
2,848 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,92 @@ | ||
import type { MasterPlaylist, Variant } from "./parser"; | ||
import type { SessionFilter } from "./session"; | ||
import type { MasterPlaylist } from "./parser"; | ||
|
||
const FILTER_VARIANTS_OPERATOR = { | ||
"<": (a: number, b: number) => a < b, | ||
"<=": (a: number, b: number) => a <= b, | ||
">": (a: number, b: number) => a > b, | ||
">=": (a: number, b: number) => a >= b, | ||
} as const; | ||
export interface Filter { | ||
resolution?: string; | ||
audioLanguage?: string; | ||
} | ||
|
||
function parseRange(input: string): [number, number] | null { | ||
const match = input.match(/^(\d+)-(\d+)$/); | ||
|
||
function getResolutionFilter( | ||
resolution: string, | ||
): [number, (a: number, b: number) => boolean] { | ||
const [operator, value] = resolution.split(" "); | ||
if (!value) { | ||
throw new Error(`Failed to parse operator / value pair "${value}"`); | ||
if (match?.[1] && match[2]) { | ||
const min = parseInt(match[1]); | ||
const max = parseInt(match[2]); | ||
return [min, max]; | ||
} | ||
|
||
const height = parseInt(value, 10); | ||
return null; | ||
} | ||
|
||
function parseOperatorToRange(input: string): [number, number] | null { | ||
const match = input.match(/(<=?|>=?)\s*(\d+)/); | ||
if (match?.[2] === undefined) { | ||
return null; | ||
} | ||
|
||
const fn = | ||
FILTER_VARIANTS_OPERATOR[operator as keyof typeof FILTER_VARIANTS_OPERATOR]; | ||
const operator = match[1]; | ||
const number = parseInt(match[2]); | ||
|
||
if (Number.isNaN(height) || !fn) { | ||
throw new Error(`Resolution filter with value "${resolution}" is invalid.`); | ||
if (operator === "<=") { | ||
return [0, number]; | ||
} else if (operator === "<") { | ||
return [0, number - 1]; | ||
} else if (operator === ">=") { | ||
return [number, Infinity]; | ||
} else if (operator === ">") { | ||
return [number + 1, Infinity]; | ||
} | ||
|
||
return [height, fn]; | ||
return null; | ||
} | ||
|
||
function filterVariantsByResolution(variants: Variant[], resolution: string) { | ||
const [height, fn] = getResolutionFilter(resolution); | ||
return variants.filter( | ||
(item) => item.resolution && fn(item.resolution.height, height), | ||
); | ||
function parseFilterToRange(input: string): [number, number] { | ||
let range = parseRange(input); | ||
if (range) { | ||
return range; | ||
} | ||
|
||
range = parseOperatorToRange(input); | ||
if (range) { | ||
return range; | ||
} | ||
|
||
throw new Error(`Failed to parse to range "${input}"`); | ||
} | ||
|
||
function parseFilterToList(input: string) { | ||
return input.split(",").map((value) => value.trim()); | ||
} | ||
|
||
export function filterMaster(master: MasterPlaylist, filter: SessionFilter) { | ||
if (filter.resolution) { | ||
master.variants = filterVariantsByResolution( | ||
master.variants, | ||
filter.resolution, | ||
export function filterMasterPlaylist(master: MasterPlaylist, filter: Filter) { | ||
if (filter.resolution !== undefined) { | ||
const [min, max] = parseFilterToRange(filter.resolution); | ||
master.variants = master.variants.filter( | ||
(variant) => | ||
// If we have no height, we'll make it pass. | ||
!variant.resolution?.height || | ||
// If the variant height is within our range. | ||
(variant.resolution.height >= min && variant.resolution.height <= max), | ||
); | ||
} | ||
if (filter.audioLanguage !== undefined) { | ||
const list = parseFilterToList(filter.audioLanguage); | ||
master.variants.filter((variant) => { | ||
variant.audio = variant.audio.filter( | ||
(audio) => !audio.language || list.includes(audio.language), | ||
); | ||
}); | ||
} | ||
} | ||
|
||
export function validateFilter(filter: SessionFilter) { | ||
if (filter.resolution) { | ||
getResolutionFilter(filter.resolution); | ||
export function extractFilterFromQuery(query: Record<string, string>) { | ||
const filter: Filter = {}; | ||
|
||
if ("filter.resolution" in query) { | ||
filter.resolution = query["filter.resolution"]; | ||
} | ||
if ("filter.audioLanguage" in query) { | ||
filter.audioLanguage = query["filter.audioLanguage"]; | ||
} | ||
|
||
return filter; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Cryptr from "cryptr"; | ||
import { env } from "../env"; | ||
|
||
const cryptr = new Cryptr(env.SUPER_SECRET ?? "__UNSECURE__", { | ||
encoding: "base64", | ||
}); | ||
|
||
export function encrypt(value: string) { | ||
return cryptr.encrypt(value); | ||
} | ||
|
||
export function decrypt(value: string) { | ||
return cryptr.decrypt(value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.