spectatr-player-sdk
Version:
A custom video player built with Stencil with Shaka Player integration
151 lines (150 loc) • 6.12 kB
JavaScript
// @ts-ignore
import shaka from "shaka-player";
import { fetchVideoSrc } from "../../services/videoService";
import { setUpPlayerEventListener } from "./event-handlers";
import { setupTracks } from "./tracker-util";
function handleLiveStream(component) {
if (!component.player.isLive()) {
console.warn('Source is not a n/ live stream!');
return;
}
component.isLive = true;
const seekRange = component.player.seekRange();
if (seekRange.end !== Infinity) {
component.videoElement.currentTime = seekRange.end;
component.duration = seekRange.end;
component.isDvrEnabled = true;
}
else {
component.videoElement.currentTime = seekRange.end ?? 0;
component.isDvrEnabled = false;
console.warn('DVR not supported for this live stream.');
}
component.progressUpdateInterval = setInterval(() => {
const newSeekRange = component.player.seekRange();
if (newSeekRange.end !== Infinity && newSeekRange.end >= component.duration && component.isPlaying && !component.isLoading) {
component.duration = newSeekRange.end;
}
}, 1000);
component.livePollingInterval = setInterval(() => {
if (!component.isLoading && component.isPlaying)
fetchVideoSrc(component);
}, 10000); //10 sec time polling
}
export async function setupVideo(component) {
if (!component.clientId)
return;
if (!component.videoElement)
return;
try {
component.isLoading = true;
await fetchVideoSrc(component, true);
if (!component.videoId) {
component.setVideoId && component.setVideoId(component.tempVideoId);
return;
}
if (!!component.scheduleTime && new Date(component.scheduleTime) > new Date()) {
component.scheduleTimer = setInterval(async () => {
if (new Date() >= new Date(component.scheduleTime)) {
component.showStartStream = true;
clearInterval(component.scheduleTimer);
}
}, 1000);
}
else {
component.showStartStream = false;
component.scheduleTime = null;
}
const support = await shaka.Player.probeSupport();
console.log('support.drm', support.drm);
component.player.configure({
// Common configuration
abr: { enabled: true },
streaming: {
bufferingGoal: 60, // Larger buffer for live streams
rebufferingGoal: 2,
bufferBehind: 30, // Keep 30s of buffer behind the playhead
ignoreTextStreamFailures: true, // Avoid failures if subtitles are missing
preferNativeHls: true, // ← Replaces useNativeHlsOnSafari
useNativeHlsForFairPlay: true,
},
manifest: {
hls: {
defaultAudioCodec: 'mp4a.40.2',
},
},
drm: !!component.token
? {
servers: {
'com.widevine.alpha': 'https://drm-widevine-licensing.axprod.net/AcquireLicense',
'com.apple.fps.1_0': 'https://drm-fairplay-licensing.axprod.net/AcquireLicense',
},
advanced: {
'com.apple.fps.1_0': {
serverCertificateUri: 'https://vtb.axinom.com/FPScert/fairplay.cer',
},
},
}
: undefined,
});
if (!!component.token) {
component.player.getNetworkingEngine().registerRequestFilter((type, request) => {
if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
return;
}
// Axinom-specific headers
request.headers['X-AxDRM-Message'] = component.token;
request.headers['Content-Type'] = 'application/octet-stream';
// For FairPlay specifically
if (request.uris[0].includes('fairplay')) {
request.headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
});
}
if (!component.scheduleTime || new Date() >= new Date(component.scheduleTime))
await loadSrc(component);
}
catch (error) {
component.isLoading = false;
component.livePollingInterval = null;
component.reactionPollingInterval = null;
console.error('Error loading video:', error);
component.videoError.emit('Error loading video');
await component.player.load('');
}
}
export async function loadSrc(component) {
component.isLoading = true;
await component.player.load(component.src.replace('https://stg-highlights-storage.s3.ap-south-1.amazonaws.com', 'https://d20mh0n8ctk3v.cloudfront.net'));
component.isLoading = false;
component.showStartStream = false;
component.duration = component.videoElement.duration;
setupTracks(component);
if (component.videoElement.paused && (component.isPlaying || !!component.scheduleTime)) {
component.scheduleTime = null;
component.videoElement.play();
}
if (component.livePollingInterval) {
clearInterval(component.livePollingInterval);
component.livePollingInterval = null;
}
if (component.progressUpdateInterval) {
clearInterval(component.progressUpdateInterval);
component.progressUpdateInterval = null;
}
if (component.reactionPollingInterval) {
clearInterval(component.reactionPollingInterval);
component.reactionPollingInterval = null;
}
// component.reactionPollingInterval = setInterval(() => {
// pollVideoReactionCount(component);
// }, 30000);
if (component.player.isLive()) {
handleLiveStream(component);
}
else {
component.isDvrEnabled = true;
}
setUpPlayerEventListener(component);
}
//# sourceMappingURL=setup-utils.js.map