-
-
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.
- Loading branch information
Showing
6 changed files
with
218 additions
and
2 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { HlsPlayer } from "@superstreamer/player/player"; | ||
import { useEffect, useRef, useState } from "react"; | ||
|
||
interface PlayerTestProps { | ||
url?: string | null; | ||
} | ||
|
||
export function PlayerTest({ url }: PlayerTestProps) { | ||
const ref = useRef<HTMLDivElement>(null); | ||
const [player, setPlayer] = useState<HlsPlayer | null>(null); | ||
|
||
useEffect(() => { | ||
const player = new HlsPlayer(ref.current!); | ||
setPlayer(player); | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (!player || !url) { | ||
return; | ||
} | ||
player.load(url); | ||
return () => { | ||
player.reset(); | ||
}; | ||
}, [player, url]); | ||
|
||
return <div className="relative aspect-video bg-black" ref={ref} />; | ||
} |
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
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,111 @@ | ||
interface Target { | ||
addEventListener?: Handler; | ||
removeEventListener?: Handler; | ||
on?: Handler; | ||
off?: Handler; | ||
} | ||
|
||
type AddCallback<T extends Target> = T extends { addEventListener: Handler } | ||
? T["addEventListener"] | ||
: T extends { on: Handler } | ||
? T["on"] | ||
: Handler; | ||
|
||
type RemoveCallback<T extends Target> = T extends { | ||
removeEventListener: Handler; | ||
} | ||
? T["removeEventListener"] | ||
: T extends { off: Handler } | ||
? T["off"] | ||
: Handler; | ||
|
||
export class EventManager { | ||
private bindings_ = new Set<Binding>(); | ||
|
||
listen = <T extends Target>(target: T) => | ||
((type, listener, context) => { | ||
const binding = createBinding(target, type, listener, context); | ||
this.bindings_.add(binding); | ||
}) as AddCallback<T>; | ||
|
||
listenOnce = <T extends Target>(target: T) => | ||
((type, listener, context) => { | ||
const binding = createBinding(target, type, listener, context, true); | ||
this.bindings_.add(binding); | ||
}) as AddCallback<T>; | ||
|
||
unlisten = <T extends Target>(target: T) => | ||
((type, listener) => { | ||
const binding = Array.from(this.bindings_).find( | ||
(binding) => | ||
binding.target === target && | ||
binding.type === type && | ||
binding.listener === listener, | ||
); | ||
if (binding) { | ||
binding.remove(); | ||
this.bindings_.delete(binding); | ||
} | ||
}) as RemoveCallback<T>; | ||
|
||
removeAll() { | ||
this.bindings_.forEach((binding) => { | ||
binding.remove(); | ||
}); | ||
this.bindings_.clear(); | ||
} | ||
} | ||
|
||
/** | ||
* Create a binding for a specific target. | ||
* @param target | ||
* @param type | ||
* @param listener | ||
* @param context | ||
* @param once | ||
* @returns | ||
*/ | ||
function createBinding( | ||
target: Target, | ||
type: string, | ||
listener: Handler, | ||
context?: unknown, | ||
once?: boolean, | ||
) { | ||
const methodMap = { | ||
add: target.addEventListener?.bind(target) ?? target.on?.bind(target), | ||
remove: | ||
target.removeEventListener?.bind(target) ?? target.off?.bind(target), | ||
}; | ||
|
||
const remove = () => { | ||
methodMap.remove?.(type, callback); | ||
}; | ||
|
||
const callback = async (...args: unknown[]) => { | ||
try { | ||
await listener.apply(context, args); | ||
if (once) { | ||
remove(); | ||
} | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
}; | ||
|
||
methodMap.add?.(type, callback); | ||
|
||
return { | ||
target, | ||
type, | ||
listener, | ||
context, | ||
once, | ||
remove, | ||
}; | ||
} | ||
|
||
type Binding = ReturnType<typeof createBinding>; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type Handler = (...args: any) => any; |
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,72 @@ | ||
import Hls from "hls.js"; | ||
import { EventManager } from "./event-manager"; | ||
|
||
export class HlsPlayer { | ||
private media_: HTMLMediaElement; | ||
|
||
private assetMedias_: [HTMLMediaElement, HTMLMediaElement]; | ||
|
||
private hlsMap_ = new Map<HTMLMediaElement, Hls>(); | ||
|
||
private eventManager_ = new EventManager(); | ||
|
||
constructor(public container: HTMLDivElement) { | ||
this.media_ = this.createMedia_(); | ||
|
||
this.assetMedias_ = [this.createMedia_(), this.createMedia_()]; | ||
|
||
this.setActiveMedia_(this.media_); | ||
} | ||
|
||
private createMedia_() { | ||
const media = document.createElement("video"); | ||
this.container.appendChild(media); | ||
|
||
media.style.position = "absolute"; | ||
media.style.inset = "0"; | ||
media.style.width = "100%"; | ||
media.style.height = "100%"; | ||
|
||
return media; | ||
} | ||
|
||
load(url: string) { | ||
const hls = new Hls(); | ||
hls.attachMedia(this.media_); | ||
|
||
this.hlsMap_.set(this.media_, hls); | ||
|
||
this.bindListeners_(hls); | ||
|
||
hls.loadSource(url); | ||
} | ||
|
||
reset() { | ||
this.eventManager_.removeAll(); | ||
|
||
const hls = this.hlsMap_.get(this.media_); | ||
if (hls) { | ||
hls.destroy(); | ||
this.hlsMap_.delete(this.media_); | ||
} | ||
} | ||
|
||
private bindListeners_(hls: Hls) { | ||
const listen = this.eventManager_.listen(hls); | ||
|
||
listen(Hls.Events.MANIFEST_LOADED, () => { | ||
console.log("LOADED IT"); | ||
}); | ||
|
||
listen(Hls.Events.INTERSTITIAL_ASSET_PLAYER_CREATED, (event) => {}); | ||
|
||
listen(Hls.Events.INTERSTITIAL_ASSET_STARTED, () => {}); | ||
} | ||
|
||
private setActiveMedia_(media: HTMLMediaElement) { | ||
const allMedias = [this.media_, ...this.assetMedias_]; | ||
allMedias.forEach((element) => { | ||
element.style.opacity = element === media ? "1" : "0"; | ||
}); | ||
} | ||
} |
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