From ec7ab15ea5d02b63b7a6580cd672b34aa91e4006 Mon Sep 17 00:00:00 2001 From: Slobodan Klentikov Date: Wed, 27 Jul 2022 11:40:45 +0200 Subject: [PATCH 1/3] Add DRM initialisation and option for drm headers --- lib/src/web/video_js_controller.dart | 27 +++++++++++++++++--- lib/src/web/video_js_scripts.dart | 38 ++++++++++++++-------------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/lib/src/web/video_js_controller.dart b/lib/src/web/video_js_controller.dart index dc04689..0501bda 100644 --- a/lib/src/web/video_js_controller.dart +++ b/lib/src/web/video_js_controller.dart @@ -71,11 +71,32 @@ class VideoJsController { /// to set video source by type /// [type] can be video/mp4, video/webm, application/x-mpegURL (for hls videos), ... - setSRC(String src, {required String type, Map? keySystems}) { + setSRC( + String src, { + required String type, + Map? keySystems, + Map? emeHeaders, + }) { + { + final html.Element scriptElement = html.ScriptElement() + ..id = 'setupDrm' + ..innerHtml = VideoJsScripts().setupDrm(playerId); + final html.Element? ele = html.querySelector('#setupDrm'); + if (html.querySelector('#setupDrm') != null) { + ele!.remove(); + } + html.querySelector('body')!.children.add(scriptElement); + } + final jsCode = VideoJsScripts().setSRCCode( + playerId, + src: src, + type: type, + keySystems: keySystems, + emeHeaders: emeHeaders, + ); final html.Element scriptElement = html.ScriptElement() ..id = 'setSRC' - ..innerHtml = - VideoJsScripts().setSRCCode(playerId, src, type, keySystems); + ..innerHtml = jsCode; final html.Element? ele = html.querySelector('#setSRC'); if (html.querySelector('#setSRC') != null) { ele!.remove(); diff --git a/lib/src/web/video_js_scripts.dart b/lib/src/web/video_js_scripts.dart index f2a06b2..1fecaa4 100644 --- a/lib/src/web/video_js_scripts.dart +++ b/lib/src/web/video_js_scripts.dart @@ -1,10 +1,13 @@ +import 'dart:convert'; + class VideoJsScripts { String videojsCode(String playerId, Map? options) { // print("videojsCode -> ${options}"); return """ var player = videojs('$playerId', $options,function() { callBackToDartSide('$playerId', 'onReady' , 'true'); - });"""; + }); + """; } String globalAutoSetup(bool status) => """ @@ -38,32 +41,24 @@ class VideoJsScripts { // String isDispose(String playerId) => """ // '$playerId'.isDisposed();"""; - String setSRCCode(String playerId, String src, String type, Map? keySystems) { - // If keySystems is not null, we assume that we need to add DRM properties - if (keySystems != null) { - return """ - - var player = videojs('$playerId'); - player.eme(); - player.src({ - type: '$type', - src: '$src', - keySystems: $keySystems - }); - - """; - } else { - return """ + String setSRCCode( + String playerId, { + required String src, + required String type, + Map? keySystems, + Map? emeHeaders, + }) => + """ var player = videojs('$playerId'); player.src({ type: '$type', src: '$src', + ${keySystems != null ? 'keySystems: ${jsonEncode(keySystems)},' : ''} + ${emeHeaders != null ? 'emeHeaders: ${jsonEncode(emeHeaders)},' : ''} }); """; - } - } //Array of Source Objects: To provide multiple versions of the source so that it can be played //using HTML5 across browsers you can use an array of source objects. Video.js will detect which @@ -76,6 +71,11 @@ class VideoJsScripts { // {type: 'video/ogg', src: 'http://www.example.com/path/to/video.ogv'} // ]); """; + String setupDrm(String playerId) => """ + var player = videojs.getPlayer('$playerId'); + player.eme(); + """; + //volume 0 until 1 String getVolume(String playerId) => """ var player = videojs.getPlayer('$playerId'); From 5bf6c1e8cea4468873efc469dca68d6b5f7ffae9 Mon Sep 17 00:00:00 2001 From: Slobodan Klentikov Date: Wed, 27 Jul 2022 11:45:59 +0200 Subject: [PATCH 2/3] Fix videojs wrapper div ids --- lib/src/web/video_js_controller.dart | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/src/web/video_js_controller.dart b/lib/src/web/video_js_controller.dart index 0501bda..7fad458 100644 --- a/lib/src/web/video_js_controller.dart +++ b/lib/src/web/video_js_controller.dart @@ -6,21 +6,23 @@ import 'package:video_js/src/models/videoJs_options.dart'; import 'package:video_js/src/web/video_js_scripts.dart'; import 'package:video_js/src/web/video_results.dart'; +const videoJsWrapperId = '#videoJsWrapper'; + class VideoJsController { final String playerId; final VideoJsOptions? videoJsOptions; late String textureId; - late html.Element playerElement; + late html.DivElement playerWrapperElement; VideoJsController(this.playerId, {this.videoJsOptions}) { - final html.Element? ele = html.querySelector('#divId'); - if (html.querySelector('#divId') != null) { + final html.Element? ele = html.querySelector(videoJsWrapperId); + if (html.querySelector(videoJsWrapperId) != null) { ele!.remove(); } textureId = _generateRandomString(7); - playerElement = html.DivElement() - ..id = 'videoElement-$textureId' + playerWrapperElement = html.DivElement() + ..id = videoJsWrapperId ..style.width = '100%' ..style.height = '100%' ..children = [ @@ -40,7 +42,7 @@ class VideoJsController { // ignore: undefined_prefixed_name ui.platformViewRegistry - .registerViewFactory(textureId, (int id) => playerElement); + .registerViewFactory(textureId, (int id) => playerWrapperElement); } Map _getVideoJsOptions(VideoJsOptions? videoJsOptions) { @@ -350,8 +352,8 @@ class VideoJsController { /// This method is available on all Video.js players and components. /// It is the only supported method of removing a Video.js player from both the DOM and memory. dispose() { - final html.Element? playerElement = html.querySelector('#divId'); - if (html.querySelector('#divId') != null) { + final html.Element? playerElement = html.querySelector(videoJsWrapperId); + if (html.querySelector(videoJsWrapperId) != null) { playerElement!.remove(); } From 6ee7b5f9e95fdb528a1eec2624c9d935ce072b9f Mon Sep 17 00:00:00 2001 From: Slobodan Klentikov Date: Wed, 27 Jul 2022 12:24:18 +0200 Subject: [PATCH 3/3] Refactor controller scripts --- lib/src/web/html_scripts.dart | 21 ++ lib/src/web/video_js_controller.dart | 305 +++++++++------------------ 2 files changed, 121 insertions(+), 205 deletions(-) create mode 100644 lib/src/web/html_scripts.dart diff --git a/lib/src/web/html_scripts.dart b/lib/src/web/html_scripts.dart new file mode 100644 index 0000000..d3d793f --- /dev/null +++ b/lib/src/web/html_scripts.dart @@ -0,0 +1,21 @@ +import 'dart:html' as html; + +removeElementIfExist(String id) { + final ele = html.querySelector('#$id'); + if (html.querySelector('#$id') != null) { + ele!.remove(); + } +} + +addElement(html.Element element) { + html.querySelector('body')!.children.add(element); +} + +replaceScriptElement(String id, String code) { + removeElementIfExist(id); + addElement( + html.ScriptElement() + ..id = id + ..innerHtml = code, + ); +} diff --git a/lib/src/web/video_js_controller.dart b/lib/src/web/video_js_controller.dart index 7fad458..e88f401 100644 --- a/lib/src/web/video_js_controller.dart +++ b/lib/src/web/video_js_controller.dart @@ -3,10 +3,11 @@ import 'dart:math'; import 'dart:ui' as ui; import 'package:video_js/src/models/videoJs_options.dart'; +import 'package:video_js/src/web/html_scripts.dart'; import 'package:video_js/src/web/video_js_scripts.dart'; import 'package:video_js/src/web/video_results.dart'; -const videoJsWrapperId = '#videoJsWrapper'; +const videoJsWrapperId = 'videoJsWrapper'; class VideoJsController { final String playerId; @@ -15,10 +16,7 @@ class VideoJsController { late html.DivElement playerWrapperElement; VideoJsController(this.playerId, {this.videoJsOptions}) { - final html.Element? ele = html.querySelector(videoJsWrapperId); - if (html.querySelector(videoJsWrapperId) != null) { - ele!.remove(); - } + removeElementIfExist(videoJsWrapperId); textureId = _generateRandomString(7); playerWrapperElement = html.DivElement() @@ -59,15 +57,10 @@ class VideoJsController { /// This function is for initial a video.js instance with options videoJs(Function(String) onReady, {VideoJsOptions? videoJsOptions}) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'videojs' - ..innerHtml = - VideoJsScripts().videojsCode(playerId, videoJsOptions?.toJson()); - final html.Element? ele = html.querySelector('#videojs'); - if (html.querySelector('#videojs') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'videojs', + VideoJsScripts().videojsCode(playerId, videoJsOptions?.toJson()), + ); VideoJsResults().listenToValueFromJs(playerId, 'onReady', onReady); } @@ -79,291 +72,193 @@ class VideoJsController { Map? keySystems, Map? emeHeaders, }) { - { - final html.Element scriptElement = html.ScriptElement() - ..id = 'setupDrm' - ..innerHtml = VideoJsScripts().setupDrm(playerId); - final html.Element? ele = html.querySelector('#setupDrm'); - if (html.querySelector('#setupDrm') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); - } - final jsCode = VideoJsScripts().setSRCCode( - playerId, - src: src, - type: type, - keySystems: keySystems, - emeHeaders: emeHeaders, + replaceScriptElement( + 'setupDrm', + VideoJsScripts().setupDrm(playerId), + ); + + replaceScriptElement( + 'setSrc', + VideoJsScripts().setSRCCode( + playerId, + src: src, + type: type, + keySystems: keySystems, + emeHeaders: emeHeaders, + ), ); - final html.Element scriptElement = html.ScriptElement() - ..id = 'setSRC' - ..innerHtml = jsCode; - final html.Element? ele = html.querySelector('#setSRC'); - if (html.querySelector('#setSRC') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); } /// To get volume of video - getVolume(Function(String) onVolumeRecive) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'getVolume' - ..innerHtml = VideoJsScripts().getVolume(playerId); - final html.Element? ele = html.querySelector('#getVolume'); - if (html.querySelector('#getVolume') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); - VideoJsResults().listenToValueFromJs(playerId, 'getVolume', onVolumeRecive); + getVolume(Function(String) onVolumeReceive) { + replaceScriptElement('getVolume', VideoJsScripts().getVolume(playerId)); + VideoJsResults() + .listenToValueFromJs(playerId, 'getVolume', onVolumeReceive); } /// set volume to video player setVolume(String volume) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'setVolume' - ..innerHtml = VideoJsScripts().setVolume(playerId, volume); - final html.Element? ele = html.querySelector('#setVolume'); - if (html.querySelector('#setVolume') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'setVolume', + VideoJsScripts().setVolume(playerId, volume), + ); } /// toggle mute in video player. if player is mute, makes unmute and if is unmute makes mute toggleMute() { - final html.Element scriptElement = html.ScriptElement() - ..id = 'toggleMute' - ..innerHtml = VideoJsScripts().toggleMute(playerId); - final html.Element? ele = html.querySelector('#toggleMute'); - if (html.querySelector('#toggleMute') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'toggleMute', + VideoJsScripts().toggleMute(playerId), + ); } /// this function is for check video player mute status isMute(Function(String) onMuteStatus) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'isMute' - ..innerHtml = VideoJsScripts().isMute(playerId); - final html.Element? ele = html.querySelector('#isMute'); - if (html.querySelector('#isMute') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'isMute', + VideoJsScripts().isMute(playerId), + ); VideoJsResults().listenToValueFromJs(playerId, 'isMute', onMuteStatus); } /// toggle full screen in video player. this function is different with requestFullScreen, /// this function just change type toggleFullScreen() { - final html.Element scriptElement = html.ScriptElement() - ..id = 'toggleFullScreen' - ..innerHtml = VideoJsScripts().toggleFullScreenMode(playerId); - final html.Element? ele = html.querySelector('#toggleFullScreen'); - if (html.querySelector('#toggleFullScreen') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'toggleFullScreen', + VideoJsScripts().toggleFullScreenMode(playerId), + ); } /// this function is for check video player full screen status isFullScreen(Function(String) onFullScreenStatus) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'isFullScreen' - ..innerHtml = VideoJsScripts().isFullScreen(playerId); - final html.Element? ele = html.querySelector('#isFullScreen'); - if (html.querySelector('#isFullScreen') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'isFullScreen', + VideoJsScripts().isFullScreen(playerId), + ); + VideoJsResults() .listenToValueFromJs(playerId, 'isFull', onFullScreenStatus); } /// To change player to full screen mode requestFullScreen() { - final html.Element scriptElement = html.ScriptElement() - ..id = 'requestFullScreen' - ..innerHtml = VideoJsScripts().requestFullscreen(playerId); - final html.Element? ele = html.querySelector('#requestFullScreen'); - if (html.querySelector('#requestFullScreen') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'requestFullScreen', + VideoJsScripts().requestFullscreen(playerId), + ); } /// To exit from full screen mode exitFullScreen() { - final html.Element scriptElement = html.ScriptElement() - ..id = 'exiteFullScreen' - ..innerHtml = VideoJsScripts().exitFullscreen(playerId); - final html.Element? ele = html.querySelector('#exiteFullScreen'); - if (html.querySelector('#exiteFullScreen') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'exitFullScreen', + VideoJsScripts().exitFullscreen(playerId), + ); } /// play video play() { - final html.Element scriptElement = html.ScriptElement() - ..id = 'play' - ..innerHtml = VideoJsScripts().play(playerId); - final html.Element? ele = html.querySelector('#play'); - if (html.querySelector('#play') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'play', + VideoJsScripts().play(playerId), + ); } /// pause video pause() { - final html.Element scriptElement = html.ScriptElement() - ..id = 'pause' - ..innerHtml = VideoJsScripts().pause(playerId); - final html.Element? ele = html.querySelector('#pause'); - if (html.querySelector('#pause') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'pause', + VideoJsScripts().pause(playerId), + ); } /// To check video player pause status isPaused(Function(String) onPauseStatus) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'isPaused' - ..innerHtml = VideoJsScripts().isPause(playerId); - final html.Element? ele = html.querySelector('#isPaused'); - if (html.querySelector('#isPaused') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'isPaused', + VideoJsScripts().isPause(playerId), + ); VideoJsResults().listenToValueFromJs(playerId, 'isPaused', onPauseStatus); } /// To get video's current playing time in seconds currentTime(Function(String) onCurrentTime) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'currentTime' - ..innerHtml = VideoJsScripts().getCurrentTime(playerId); - final html.Element? ele = html.querySelector('#currentTime'); - if (html.querySelector('#currentTime') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'currentTime', + VideoJsScripts().getCurrentTime(playerId), + ); VideoJsResults().listenToValueFromJs(playerId, 'getCurrent', onCurrentTime); } /// Set video setCurrentTime(String currentTime) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'setCurrentTime' - ..innerHtml = VideoJsScripts().setCurrentTime(playerId, currentTime); - final html.Element? ele = html.querySelector('#setCurrentTime'); - if (html.querySelector('#setCurrentTime') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'setCurrentTime', + VideoJsScripts().setCurrentTime(playerId, currentTime), + ); } /// Video whole time in seconds durationTime(Function(String) onDurationTime) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'durationTime' - ..innerHtml = VideoJsScripts().duration(playerId); - final html.Element? ele = html.querySelector('#durationTime'); - if (html.querySelector('#durationTime') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'durationTime', + VideoJsScripts().duration(playerId), + ); VideoJsResults() .listenToValueFromJs(playerId, 'getDuration', onDurationTime); } /// Video remain time in seconds remainTime(Function(String) onRemainTime) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'onRemainTime' - ..innerHtml = VideoJsScripts().remainingTime(playerId); - final html.Element? ele = html.querySelector('#onRemainTime'); - if (html.querySelector('#onRemainTime') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'onRemainTime', + VideoJsScripts().remainingTime(playerId), + ); VideoJsResults() .listenToValueFromJs(playerId, 'getRemaining', onRemainTime); } /// Video buffered ( downloaded ) percent bufferPercent(Function(String) onBufferPercent) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'bufferPercent' - ..innerHtml = VideoJsScripts().bufferedPercent(playerId); - final html.Element? ele = html.querySelector('#bufferPercent'); - if (html.querySelector('#bufferPercent') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'bufferPercent', + VideoJsScripts().bufferedPercent(playerId), + ); VideoJsResults() .listenToValueFromJs(playerId, 'getBuffered', onBufferPercent); } /// Set Video poster/thumbnail setPoster(String poster) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'setPoster' - ..innerHtml = VideoJsScripts().setPoster(playerId, poster); - final html.Element? ele = html.querySelector('#setPoster'); - if (html.querySelector('#setPoster') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'setPoster', + VideoJsScripts().setPoster(playerId, poster), + ); } /// Get Video poster/thumbnail getPoster(Function(String) onPosterGet) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'getPoster' - ..innerHtml = VideoJsScripts().getPoster(playerId); - final html.Element? ele = html.querySelector('#getPoster'); - if (html.querySelector('#getPoster') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'getPoster', + VideoJsScripts().getPoster(playerId), + ); VideoJsResults().listenToValueFromJs(playerId, 'getPoster', onPosterGet); } /// Get Video poster/thumbnail onPlayerReady(Function(String) onReady) { - final html.Element scriptElement = html.ScriptElement() - ..id = 'onPlayerReady' - ..innerHtml = VideoJsScripts().getPoster(playerId); - final html.Element? ele = html.querySelector('#onPlayerReady'); - if (html.querySelector('#onPlayerReady') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + replaceScriptElement( + 'onPlayerReady', + VideoJsScripts().getPoster(playerId), + ); VideoJsResults().listenToValueFromJs(playerId, 'onReady', onReady); } /// This method is available on all Video.js players and components. /// It is the only supported method of removing a Video.js player from both the DOM and memory. dispose() { - final html.Element? playerElement = html.querySelector(videoJsWrapperId); - if (html.querySelector(videoJsWrapperId) != null) { - playerElement!.remove(); - } - - final html.Element scriptElement = html.ScriptElement() - ..id = 'dispose' - ..innerHtml = VideoJsScripts().dispose(playerId); - final html.Element? ele = html.querySelector('#dispose'); - if (html.querySelector('#dispose') != null) { - ele!.remove(); - } - html.querySelector('body')!.children.add(scriptElement); + removeElementIfExist(videoJsWrapperId); + replaceScriptElement('dispose', VideoJsScripts().dispose(playerId)); } }