1.2.27 • Published 1 year ago

@k90mirzaei/video-player v1.2.27

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

// Sure, here's an example React component written in TypeScript that plays the HLS playlist you provided using the video.js library and the crypto-js library for decryption. This component follows the SOLID principles by separating concerns into smaller, more focused classes.

import React, { useEffect, useRef } from 'react'; import videojs, { VideoJsPlayerOptions } from 'video.js' import CryptoJS from 'crypto-js';

type Props = { playlistUrl: string; keyUrl: string; };

class Decrypter { private key: CryptoJS.WordArray; private iv: CryptoJS.WordArray;

constructor(keyUrl: string, iv: string) { const xhr = new XMLHttpRequest(); xhr.open('GET', keyUrl, false); xhr.send(); const keyHex = xhr.responseText; this.key = CryptoJS.enc.Hex.parse(keyHex); this.iv = CryptoJS.enc.Hex.parse(iv); }

decrypt(data: Uint8Array): Uint8Array { const encrypted = CryptoJS.lib.WordArray.create(data); const decrypted = CryptoJS.AES.decrypt({ ciphertext: encrypted }, this.key, { iv: this.iv }); return new Uint8Array(decrypted.sigBytes); } }

class HlsPlaylist { private segments: Array<{ duration: number, uri: string, key?: { uri: string, iv: string } }>;

constructor(playlistUrl: string) { const xhr = new XMLHttpRequest(); xhr.open('GET', playlistUrl, false); xhr.send(); const playlistText = xhr.responseText; const lines = playlistText.trim().split('\n'); const segments: Array<{ duration: number, uri: string, key?: { uri: string, iv: string } }> = []; let currentKey: { uri: string, iv: string } | undefined = undefined; for (let i = 0; i < lines.length; i++) { const line = linesi; if (line.startsWith('#EXT-X-KEY:')) { const matches = /METHOD=AES-128,URI="(^"+)",IV=(0-9a-fA-F+)/.exec(line); if (matches) { currentKey = { uri: matches1, iv: matches2 }; } else { console.warn('Could not parse key info:', line); } } else if (line.startsWith('#EXTINF:')) { const matches = /^#EXTINF:(0-9.+),/.exec(line); if (matches) { const duration = parseFloat(matches1); const uri = linesi + 1; segments.push({ duration, uri, key: currentKey }); currentKey = undefined; } else { console.warn('Could not parse segment info:', line); } } } this.segments = segments; }

getSegmentUrl(index: number): string | undefined { return this.segmentsindex?.uri; }

getSegmentDuration(index: number): number | undefined { return this.segmentsindex?.duration; }

getSegmentKey(index: number): Decrypter | undefined { const keyInfo = this.segmentsindex?.key; if (keyInfo) { return new Decrypter(keyInfo.uri, keyInfo.iv); } }

getSegmentCount(): number { return this.segments.length; } }

class HlsPlayer { private playlist: HlsPlaylist; private player: videojs.Player; private currentSegment: number = 0;

constructor(playlistUrl: string, keyUrl: string, videoElement: HTMLVideoElement) { this.playlist = new HlsPlaylist(playlistUrl); const options: VideoJsPlayerOptions = { sources: { src: this.playlist.getSegmentUrl(0) ?? '', type: 'application/vnd.apple.mpegurl', }, html5: { hls: { overrideNative: true, decrypt: (encrypted: Uint8Array, key: Uint8Array, iv: Uint8Array) => { const decrypter = this.playlist.getSegmentKey(this.currentSegment); if (decrypter) { const decrypted = decrypter.decrypt(encrypted); return decrypted.buffer; } else { console.warn('No key available for decryption'); return encrypted.buffer; } }, }, }, autoplay: true, }; this.player = videojs(videoElement, options); this.player.on('ended', () => { this.currentSegment++; if (this.currentSegment < this.playlist.getSegmentCount()) { const url = this.playlist.getSegmentUrl(this.currentSegment); const duration = this.playlist.getSegmentDuration(this.currentSegment) ?? 0; const key = this.playlist.getSegmentKey(this.currentSegment); if (url) { this.player.src({ src: url, type: 'application/vnd.apple.mpegurl', }); this.player.play(); if (duration > 0) { setTimeout(() => { this.player.trigger('ended'); }, duration * 1000); } } else { console.warn('No URL available for next segment'); } } else { console.log('Playlist ended'); } }); }

start() { this.player.play(); } }

const HlsPlayerComponent: React.FC = ({ playlistUrl, keyUrl }) => { const videoRef = useRef(null);

useEffect(() => { if (!videoRef.current) { console.warn('Video element not found'); return; } const player = new HlsPlayer(playlistUrl, keyUrl, videoRef.current); player.start(); }, playlistUrl, keyUrl);

return (

<div>
  <video ref={videoRef} className="video-js vjs-default-skin vjs-big-play-centered" playsInline />
</div>

); };

export default HlsPlayerComponent; // To use this component, you can simply import it and render it like this:

import HlsPlayerComponent from './HlsPlayerComponent';

const App: React.FC = () => { return (

<div>
  <HlsPlayerComponent playlistUrl="http://mydev.test/media/16/playlist.m3u8" keyUrl="http://mydev.test/media/key/16/f12393361092e573.key" />
</div>

); };

export default App; // Note that this code assumes that the video.js and crypto-js libraries have been installed and imported correctly. You may need to adjust the import statements or add these libraries to your project if you encounter any errors.

1.2.27

1 year ago

1.2.26

1 year ago

1.2.25

1 year ago

1.2.24

1 year ago

1.2.23

1 year ago

1.2.22

1 year ago

1.2.21

1 year ago

1.2.2

1 year ago

1.2.1

1 year ago

1.2.0

1 year ago

1.1.7

1 year ago

1.1.6

1 year ago