ovenplayer 0.10.2 → 0.10.3-3.alpha-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +39 -46
  3. package/dist/ovenplayer.js +1 -1
  4. package/dist/ovenplayer.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/assets/fonts/seek-icons.svg +13 -13
  7. package/src/js/api/Api.js +231 -140
  8. package/src/js/api/Configurator.js +6 -3
  9. package/src/js/api/SupportChecker.js +9 -3
  10. package/src/js/api/constants.js +203 -15
  11. package/src/js/api/media/Manager.js +15 -106
  12. package/src/js/api/provider/Controller.js +5 -6
  13. package/src/js/api/provider/html5/Provider.js +107 -86
  14. package/src/js/api/provider/html5/providers/Dash.js +39 -110
  15. package/src/js/api/provider/html5/providers/Hls.js +139 -99
  16. package/src/js/api/provider/html5/providers/Html5.js +3 -1
  17. package/src/js/api/provider/html5/providers/WebRTC.js +207 -37
  18. package/src/js/api/provider/html5/providers/WebRTCLoader.js +247 -116
  19. package/src/js/ovenplayer.js +5 -9
  20. package/src/js/ovenplayer.sdk.js +5 -6
  21. package/src/js/utils/browser.js +6 -1
  22. package/src/js/utils/getTouchSection.js +23 -0
  23. package/src/js/utils/likeA$.js +4 -3
  24. package/src/js/utils/resize-sensor.js +168 -1
  25. package/src/js/utils/underscore.js +5 -5
  26. package/src/js/view/components/controls/fullScreenButton.js +22 -15
  27. package/src/js/view/components/controls/main.js +33 -20
  28. package/src/js/view/components/controls/playlistPanel.js +1 -1
  29. package/src/js/view/components/controls/progressBar.js +151 -76
  30. package/src/js/view/components/controls/settingButton.js +65 -48
  31. package/src/js/view/components/controls/settingPanel/audioTrackPanel.js +57 -0
  32. package/src/js/view/components/controls/settingPanel/captionPanel.js +1 -1
  33. package/src/js/view/components/controls/settingPanel/main.js +110 -80
  34. package/src/js/view/components/controls/settingPanel/qualityPanel.js +2 -2
  35. package/src/js/view/components/controls/settingPanel/sourcePanel.js +1 -1
  36. package/src/js/view/components/controls/settingPanel/speedPanel.js +1 -1
  37. package/src/js/view/components/controls/settingPanel/timeDisplayPanel.js +1 -1
  38. package/src/js/view/components/controls/timeDisplay.js +95 -23
  39. package/src/js/view/components/controls/timeDisplayTemplate.js +1 -1
  40. package/src/js/view/components/controls/volumeButton.js +2 -3
  41. package/src/js/view/components/helpers/captionViewer.js +1 -1
  42. package/src/js/view/components/helpers/contextPanel.js +1 -1
  43. package/src/js/view/components/helpers/contextPanelTemplate.js +1 -1
  44. package/src/js/view/components/helpers/main.js +21 -0
  45. package/src/js/view/components/helpers/thumbnailTemplate.js +0 -1
  46. package/src/js/view/engine/Templates.js +2 -0
  47. package/src/js/view/view.js +53 -14
  48. package/src/js/view/viewTemplate.js +8 -8
  49. package/src/stylesheet/ovenplayer.less +565 -308
@@ -7,7 +7,7 @@ import LA$ from 'utils/likeA$';
7
7
 
8
8
 
9
9
  const CaptionPanel = function($container, api, data){
10
- const $root = LA$("#"+api.getContainerId());
10
+ const $root = LA$(api.getContainerElement());
11
11
  let panelManager = PanelManager();
12
12
 
13
13
  data.setFront = function(isFront){
@@ -9,117 +9,133 @@ import sizeHumanizer from "utils/sizeHumanizer";
9
9
  import SpeedPanel from "view/components/controls/settingPanel/speedPanel";
10
10
  import SourcePanel from "view/components/controls/settingPanel/sourcePanel";
11
11
  import QualityPanel from "view/components/controls/settingPanel/qualityPanel";
12
+ import AudioTrackPanel from "view/components/controls/settingPanel/audioTrackPanel";
12
13
  import CaptionPanel from "view/components/controls/settingPanel/captionPanel";
13
14
  import TimeDisplayPanel from "view/components/controls/settingPanel/timeDisplayPanel";
14
15
  import {
15
16
  CONTENT_LEVEL_CHANGED, PROVIDER_RTMP
16
17
  } from "api/constants";
18
+ import {AUDIO_TRACK_CHANGED} from "../../../../api/constants";
17
19
 
18
20
  let PANEL_TITLE = {
19
- "speed" : "Speed",
20
- "speedUnit" : "x",
21
- "source" : "Source",
22
- "quality" : "Quality",
23
- "caption" : "Caption",
24
- "display" : "Display"
21
+ "speed": "Speed",
22
+ "speedUnit": "x",
23
+ "source": "Source",
24
+ "quality": "Quality",
25
+ "audioTrack": "Audio",
26
+ "caption": "Caption",
27
+ "display": "Display"
25
28
  };
26
29
 
27
- const Panels = function($container, api, data){
30
+ const Panels = function ($container, api, data) {
28
31
 
29
- const $root = LA$("#"+api.getContainerId());
32
+ const $root = LA$(api.getContainerElement());
30
33
  let panelManager = PanelManager();
31
34
 
32
35
  let playerConfig = api.getConfig();
33
36
 
34
- if(playerConfig && playerConfig.systemText){
37
+ if (playerConfig && playerConfig.systemText) {
35
38
  Object.keys(PANEL_TITLE).forEach(title => {
36
39
  PANEL_TITLE[title] = playerConfig.systemText.ui.setting[title];
37
40
  });
38
41
  }
39
42
 
40
- function extractSubPanelData(api, panelType){
43
+ function extractSubPanelData(api, panelType) {
41
44
  let panel = {
42
- id : "panel-"+new Date().getTime() ,
43
- title : "",
44
- body : [],
45
- useCheck : true,
46
- panelType : panelType,
47
- height : $root.height() - $root.find(".op-bottom-panel").height()
45
+ id: "panel-" + new Date().getTime(),
46
+ title: "",
47
+ body: [],
48
+ useCheck: true,
49
+ panelType: panelType,
50
+ height: $root.height() - $root.find(".op-bottom-panel").height()
48
51
  };
49
52
  panel.title = PANEL_TITLE[panelType];
50
- if(panelType === "speed"){
53
+ if (panelType === "speed") {
51
54
  let playBackRates = api.getConfig().playbackRates;
52
55
  let currentPlaybackRate = api.getPlaybackRate();
53
- for (let i = 0; i < playBackRates.length; i ++) {
56
+ for (let i = 0; i < playBackRates.length; i++) {
54
57
  let body = {
55
- title : playBackRates[i]+PANEL_TITLE.speedUnit, //(playBackRates[i] === 1? "Normal" : playBackRates[i]),
56
- isCheck : currentPlaybackRate === playBackRates[i],
57
- value : playBackRates[i],
58
- description : playBackRates[i],
59
- panelType : panelType
58
+ title: playBackRates[i] + PANEL_TITLE.speedUnit, //(playBackRates[i] === 1? "Normal" : playBackRates[i]),
59
+ isCheck: currentPlaybackRate === playBackRates[i],
60
+ value: playBackRates[i],
61
+ description: playBackRates[i],
62
+ panelType: panelType
60
63
  };
61
64
  panel.body.push(body);
62
65
  }
63
66
 
64
- }else if(panelType === "source"){
67
+ } else if (panelType === "source") {
65
68
  let sources = api.getSources();
66
- for (let i = 0; i < sources.length; i ++) {
69
+ for (let i = 0; i < sources.length; i++) {
67
70
  let body = {
68
- title : sources[i].label,
69
- isCheck : api.getCurrentSource() === i,
70
- value : i,
71
- panelType : panelType
71
+ title: sources[i].label,
72
+ isCheck: api.getCurrentSource() === i,
73
+ value: i,
74
+ panelType: panelType
72
75
  };
73
76
  panel.body.push(body);
74
77
  }
75
78
 
76
- }else if(panelType === "quality"){
79
+ } else if (panelType === "quality") {
77
80
  let qualityLevels = api.getQualityLevels();
78
81
  panel.body.push({
79
- title : "AUTO",
80
- isCheck : api.isAutoQuality(),
81
- value : "AUTO",
82
- panelType : panelType
82
+ title: "AUTO",
83
+ isCheck: api.isAutoQuality(),
84
+ value: "AUTO",
85
+ panelType: panelType
83
86
  });
84
- for (let i = 0; i < qualityLevels.length; i ++) {
87
+ for (let i = 0; i < qualityLevels.length; i++) {
85
88
  let body = {
86
- title : qualityLevels[i].label,
87
- isCheck : api.getCurrentQuality() === i,
88
- value : i,
89
- panelType : panelType
89
+ title: qualityLevels[i].label,
90
+ isCheck: api.getCurrentQuality() === i,
91
+ value: i,
92
+ panelType: panelType
90
93
  };
91
94
  panel.body.push(body);
92
95
  }
93
96
 
94
- }else if(panelType === "caption"){
97
+ } else if (panelType === "audioTrack") {
98
+ let audioTracks = api.getAudioTracks();
99
+
100
+ for (let i = 0; i < audioTracks.length; i++) {
101
+ let body = {
102
+ title: audioTracks[i].label,
103
+ isCheck: audioTracks[i].index === api.getCurrentAudioTrack(),
104
+ value: audioTracks[i].index,
105
+ panelType: panelType
106
+ };
107
+ panel.body.push(body);
108
+ }
109
+
110
+ } else if (panelType === "caption") {
95
111
  let captions = api.getCaptionList();
96
112
  panel.body.push({
97
- title : "OFF",
98
- isCheck : api.getCurrentCaption() === -1,
99
- value : -1,
100
- panelType : panelType
113
+ title: "OFF",
114
+ isCheck: api.getCurrentCaption() === -1,
115
+ value: -1,
116
+ panelType: panelType
101
117
  });
102
- for (let i = 0; i < captions.length; i ++) {
118
+ for (let i = 0; i < captions.length; i++) {
103
119
  let body = {
104
- title : captions[i].label,
105
- isCheck : api.getCurrentCaption() === i,
106
- value : i,
107
- panelType : panelType
120
+ title: captions[i].label,
121
+ isCheck: api.getCurrentCaption() === i,
122
+ value: i,
123
+ panelType: panelType
108
124
  };
109
125
  panel.body.push(body);
110
126
  }
111
127
 
112
- }else if(panelType === "display"){
128
+ } else if (panelType === "display") {
113
129
  let displayModes = [
114
130
  "Play time",
115
131
  "Framecode"
116
132
  ];
117
- for (let i = 0; i < displayModes.length; i ++) {
133
+ for (let i = 0; i < displayModes.length; i++) {
118
134
  let body = {
119
- title : displayModes[i],
120
- isCheck : api.isTimecodeMode() ? (displayModes[i] === "Play time") : (displayModes[i] === "Framecode"),
121
- value : displayModes[i],
122
- panelType : panelType
135
+ title: displayModes[i],
136
+ isCheck: api.isTimecodeMode() ? (displayModes[i] === "Play time") : (displayModes[i] === "Framecode"),
137
+ value: displayModes[i],
138
+ panelType: panelType
123
139
  };
124
140
  panel.body.push(body);
125
141
  }
@@ -128,74 +144,88 @@ const Panels = function($container, api, data){
128
144
  return panel;
129
145
  };
130
146
 
131
- data.setFront = function(isFront){
132
- if(isFront){
133
- $root.find("#"+data.id).removeClass("background");
134
- }else{
135
- $root.find("#"+data.id).addClass("background");
147
+ data.setFront = function (isFront) {
148
+ if (isFront) {
149
+ $root.find("#" + data.id).removeClass("background");
150
+ } else {
151
+ $root.find("#" + data.id).addClass("background");
136
152
  }
137
153
  };
138
- function setPanelMaxHeight(){
139
- if($root.find(".op-setting-panel")){
140
- $root.find(".op-setting-panel").css("max-height", $root.height() - $root.find(".op-bottom-panel").height() + "px");
154
+
155
+ function setPanelMaxHeight() {
156
+ if ($root.find(".op-setting-panel")) {
157
+ $root.find(".op-setting-panel").css("max-height", $root.height() - $root.find(".op-bottom-panel").height() + "px");
141
158
  }
142
159
  };
143
- const onRendered = function($current, template){
160
+ const onRendered = function ($current, template) {
144
161
  setPanelMaxHeight();
145
162
 
146
- api.on(CONTENT_LEVEL_CHANGED, function(data){
163
+ api.on(CONTENT_LEVEL_CHANGED, function (data) {
147
164
  let newQuality = data.currentQuality;
148
- if(data.type === "render" && $root.find("#"+template.data.id).find(".op-setting-item")){
149
- _.forEach( $root.find("#"+template.data.id).find(".op-setting-item").get() ||[], function(panel){
165
+ if (data.type === "render" && $root.find("#" + template.data.id).find(".op-setting-item")) {
166
+ _.forEach($root.find("#" + template.data.id).find(".op-setting-item").get() || [], function (panel) {
150
167
  let $panel = LA$(panel);
151
168
 
152
- if($panel.attr("op-panel-type") === "quality"){
169
+ if ($panel.attr("op-panel-type") === "quality") {
153
170
  let qualityList = api.getQualityLevels();
154
171
  let newQualityObject = qualityList[newQuality];
155
- $panel.find(".op-setting-item-value").text(newQualityObject.width+"x"+newQualityObject.height+", "+ sizeHumanizer(newQualityObject.bitrate, true, "bps"));
172
+ $panel.find(".op-setting-item-value").text(newQualityObject.width + "x" + newQualityObject.height + ", " + sizeHumanizer(newQualityObject.bitrate, true, "bps"));
156
173
  }
157
174
 
158
175
  });
159
176
  }
160
177
 
161
178
  }, template);
179
+
180
+ api.on(AUDIO_TRACK_CHANGED, function (data) {
181
+ _.forEach($root.find("#" + template.data.id).find(".op-setting-item").get() || [], function (panel) {
182
+
183
+ let $panel = LA$(panel);
184
+
185
+ if($panel.attr("op-panel-type") === "audioTrack"){
186
+ $panel.find(".op-setting-item-value").text(api.getAudioTracks()[data.currentAudioTrack].label);
187
+ }
188
+ });
189
+ }, template);
162
190
  };
163
- const onDestroyed = function(template){
191
+ const onDestroyed = function (template) {
164
192
  api.off(CONTENT_LEVEL_CHANGED, null, template);
193
+ api.off(AUDIO_TRACK_CHANGED, null, template);
165
194
  };
166
195
  const events = {
167
196
  "click .op-setting-item": function (event, $current, template) {
168
197
  event.preventDefault();
169
198
  //if this panel is background it disabled click.
170
- if($root.find("#"+data.id).hasClass("background")){
199
+ if ($root.find("#" + data.id).hasClass("background")) {
171
200
  return false;
172
201
  }
173
202
  let panelType = LA$(event.currentTarget).attr("op-panel-type");
174
203
  let panel = null;
175
- if(panelType === "speed"){
204
+ if (panelType === "speed") {
176
205
  panel = SpeedPanel($container, api, extractSubPanelData(api, panelType));
177
- }else if(panelType === "source"){
206
+ } else if (panelType === "source") {
178
207
  panel = SourcePanel($container, api, extractSubPanelData(api, panelType));
179
- }else if(panelType === "quality"){
208
+ } else if (panelType === "quality") {
180
209
  panel = QualityPanel($container, api, extractSubPanelData(api, panelType));
181
- }else if(panelType === "caption"){
210
+ } else if (panelType === "audioTrack") {
211
+ panel = AudioTrackPanel($container, api, extractSubPanelData(api, panelType));
212
+ } else if (panelType === "caption") {
182
213
  panel = CaptionPanel($container, api, extractSubPanelData(api, panelType));
183
- }else if(panelType === "display"){
214
+ } else if (panelType === "display") {
184
215
  panel = TimeDisplayPanel($container, api, extractSubPanelData(api, panelType));
185
216
  }
186
217
 
187
218
  panelManager.add(panel);
188
219
  },
189
- "click .op-setting-title" : function(event, $current, template){
220
+ "click .op-setting-title": function (event, $current, template) {
190
221
  event.preventDefault();
191
- if($root.find("#"+data.id).hasClass("background")){
222
+ if ($root.find("#" + data.id).hasClass("background")) {
192
223
  return false;
193
224
  }
194
225
  panelManager.removeLastItem();
195
226
  }
196
227
  };
197
-
198
- return OvenTemplate($container, "Panels", api.getConfig(), data, events, onRendered, onDestroyed );
228
+ return OvenTemplate($container, "Panels", api.getConfig(), data, events, onRendered, onDestroyed);
199
229
 
200
230
  };
201
231
 
@@ -10,7 +10,7 @@ import {
10
10
  } from "api/constants";
11
11
 
12
12
  const QualityPanel = function($container, api, data){
13
- const $root = LA$("#"+api.getContainerId());
13
+ const $root = LA$(api.getContainerElement());
14
14
  let panelManager = PanelManager();
15
15
 
16
16
  data.setFront = function(isFront){
@@ -49,7 +49,7 @@ const QualityPanel = function($container, api, data){
49
49
  event.preventDefault();
50
50
  let value = LA$(event.currentTarget).attr("op-data-value");
51
51
  if(value === "AUTO"){
52
- api.setAutoQuality(true);
52
+ api.setAutoQuality(!api.isAutoQuality());
53
53
  }else{
54
54
  api.setCurrentQuality(parseInt(value));
55
55
  }
@@ -7,7 +7,7 @@ import LA$ from 'utils/likeA$';
7
7
 
8
8
 
9
9
  const SourcePanel = function($container, api, data){
10
- const $root = LA$("#"+api.getContainerId());
10
+ const $root = LA$(api.getContainerElement());
11
11
  let panelManager = PanelManager();
12
12
 
13
13
  data.setFront = function(isFront){
@@ -7,7 +7,7 @@ import LA$ from 'utils/likeA$';
7
7
 
8
8
 
9
9
  const SpeedPanel = function($container, api, data){
10
- const $root = LA$("#"+api.getContainerId());
10
+ const $root = LA$(api.getContainerElement());
11
11
  let panelManager = PanelManager();
12
12
 
13
13
  data.setFront = function(isFront){
@@ -7,7 +7,7 @@ import LA$ from 'utils/likeA$';
7
7
 
8
8
 
9
9
  const TimeDisplayPanel = function($container, api, data){
10
- const $root = LA$("#"+api.getContainerId());
10
+ const $root = LA$(api.getContainerElement());
11
11
  let panelManager = PanelManager();
12
12
 
13
13
  data.setFront = function(isFront){
@@ -2,61 +2,133 @@
2
2
  * Created by hoho on 2018. 7. 25..
3
3
  */
4
4
  import OvenTemplate from "view/engine/OvenTemplate";
5
- import {naturalHms} from "utils/strings";
5
+ import { naturalHms } from "utils/strings";
6
6
  import {
7
7
  CONTENT_TIME,
8
- CONTENT_TIME_MODE_CHANGED
8
+ CONTENT_TIME_MODE_CHANGED,
9
+ PROVIDER_HLS,
10
+ PROVIDER_HTML5
9
11
  } from "api/constants";
10
12
 
11
- const TimeDisplay = function($container, api, data){
13
+ const TimeDisplay = function ($container, api, data) {
12
14
 
13
- let $position = "", $duration = "";
15
+ let $position = "", $duration = "", $liveBadge = "", $liveText = "";
14
16
 
15
- function convertHumanizeTime(time){
17
+ const mediaElement = api.getMediaElement();
18
+
19
+ let hlsLive = false;
20
+ let nativeHlsLive = false;
21
+
22
+ function convertHumanizeTime(time) {
16
23
  return naturalHms(time);
17
- };
24
+ }
18
25
 
19
- const onRendered = function($current, template){
26
+
27
+ function getNativeHlsDvrWindow() {
28
+ return mediaElement.seekable.end(mediaElement.seekable.length - 1) - mediaElement.seekable.start(0);
29
+ }
30
+
31
+ const onRendered = function ($current, template) {
20
32
  let isTimecode = api.isTimecodeMode();
21
33
  $position = $current.find(".op-time-current");
22
34
  $duration = $current.find(".op-time-duration");
35
+ $liveBadge = $current.find(".op-live-badge");
36
+ $liveText = $current.find(".op-live-text");
37
+
38
+ if (data && data.type === PROVIDER_HLS && data.duration === Infinity) {
39
+ hlsLive = true;
23
40
 
24
- if(data.duration !== Infinity){
41
+ if (api.getProviderName() === PROVIDER_HTML5) {
42
+ nativeHlsLive = true;
43
+ }
44
+ }
45
+
46
+ if (data.duration !== Infinity) {
25
47
 
26
- if(isTimecode){
48
+ if (isTimecode) {
27
49
  $duration.text(convertHumanizeTime(data.duration));
28
- }else{
29
- $duration.text( Math.round (data.duration * api.getFramerate()) + " ("+api.getFramerate()+"fps)");
50
+ } else {
51
+ $duration.text(Math.round(data.duration * api.getFramerate()) + " (" + api.getFramerate() + "fps)");
30
52
  }
31
53
 
32
- api.on(CONTENT_TIME_MODE_CHANGED, function(isTimecodeMode){
54
+ api.on(CONTENT_TIME_MODE_CHANGED, function (isTimecodeMode) {
33
55
  isTimecode = isTimecodeMode;
34
- if(isTimecode){
56
+ if (isTimecode) {
35
57
  $duration.text(convertHumanizeTime(data.duration));
36
- }else{
37
- $duration.text( Math.round (data.duration * api.getFramerate()) + " ("+api.getFramerate()+"fps)");
58
+ } else {
59
+ $duration.text(Math.round(data.duration * api.getFramerate()) + " (" + api.getFramerate() + "fps)");
38
60
  }
39
- },template);
61
+ }, template);
40
62
 
41
- api.on(CONTENT_TIME, function(data) {
42
- if(isTimecode){
63
+ api.on(CONTENT_TIME, function (data) {
64
+ if (isTimecode) {
43
65
  $position.text(convertHumanizeTime(data.position));
44
- }else{
45
- $position.text( Math.round (data.position * api.getFramerate()));
66
+ } else {
67
+ $position.text(Math.round(data.position * api.getFramerate()));
46
68
  }
47
- },template);
69
+ }, template);
70
+ } else {
71
+ if (hlsLive && !nativeHlsLive) {
72
+ api.on(CONTENT_TIME, function (data) {
73
+
74
+ if (data.duration - data.position > 3) {
75
+ $liveBadge.addClass('op-live-badge-delayed');
76
+ } else {
77
+ $liveBadge.removeClass('op-live-badge-delayed');
78
+ }
79
+
80
+ }, template);
81
+ } else if (hlsLive && nativeHlsLive) {
82
+
83
+ api.on(CONTENT_TIME, function (data) {
84
+ const dvrWindow = getNativeHlsDvrWindow();
85
+ if (dvrWindow - data.position > 3) {
86
+ $liveBadge.addClass('op-live-badge-delayed');
87
+ } else {
88
+ $liveBadge.removeClass('op-live-badge-delayed');
89
+ }
90
+
91
+ }, template);
92
+ }
48
93
  }
49
94
 
50
95
  };
51
- const onDestroyed = function(template){
96
+
97
+ const onDestroyed = function (template) {
52
98
  api.off(CONTENT_TIME_MODE_CHANGED, null, template);
53
99
  api.off(CONTENT_TIME, null, template);
54
100
  };
55
101
  const events = {
102
+ "click .op-live-text": function (event, $current, template) {
103
+
104
+ event.preventDefault();
105
+
106
+ api.seek(Number.MAX_SAFE_INTEGER);
107
+
108
+ //When playback get back to the latest, turn the latency control back on.
109
+ const config = api.getConfig();
110
+ if (config.hlsConfig) {
56
111
 
112
+ const hlsConfig = config.hlsConfig;
113
+ if (typeof hlsConfig.liveSyncDuration === 'number') {
114
+ api.getMseInstance().config.liveSyncDuration
115
+ = hlsConfig.liveSyncDuration;
116
+ }
117
+
118
+ if (typeof hlsConfig.liveMaxLatencyDuration === 'number') {
119
+ api.getMseInstance().config.liveMaxLatencyDuration
120
+ = hlsConfig.liveMaxLatencyDuration;
121
+ }
122
+
123
+ if (typeof hlsConfig.maxLiveSyncPlaybackRate === 'number') {
124
+ api.getMseInstance().config.maxLiveSyncPlaybackRate =
125
+ hlsConfig.maxLiveSyncPlaybackRate;
126
+ }
127
+ }
128
+ },
57
129
  };
58
130
 
59
- return OvenTemplate($container, "TimeDisplay", api.getConfig(), data, events, onRendered, onDestroyed );
131
+ return OvenTemplate($container, "TimeDisplay", api.getConfig(), data, events, onRendered, onDestroyed);
60
132
  };
61
133
 
62
134
 
@@ -10,7 +10,7 @@ export default (uiText, data) => {
10
10
  `<span class="op-live-badge-lowlatency">${uiText.controls.low_latency_p2p}</span>` : `<span class="op-live-badge-lowlatency">${uiText.controls.low_latency_live}</span>`
11
11
  )
12
12
  :
13
- `<span>${uiText.controls.live}</span>`) +
13
+ `<span class="op-live-text" title="Skip ahead to live.">${uiText.controls.live}</span>`) +
14
14
  `</span>`
15
15
  )
16
16
  :(`<span class="op-time-current">00:00</span><span class="op-time-separator"> / </span><span class="op-time-duration">00:00</span>`)
@@ -93,12 +93,11 @@ const VolumeButton = function($container, api){
93
93
 
94
94
  $sliderHandle.css("left", maxRange+ "px");
95
95
 
96
+ setVolumeUI(api.getVolume());
97
+
96
98
  api.on(READY, function() {
97
99
  setVolumeUI(api.getVolume());
98
100
  }, template);
99
- api.on(PLAYER_PLAY, function (data) {
100
- setVolumeUI(data.volume);
101
- }, template);
102
101
  api.on(CONTENT_VOLUME, function(data) {
103
102
 
104
103
  setVolumeUI(data.volume);
@@ -14,7 +14,7 @@ import LA$ from 'utils/likeA$';
14
14
 
15
15
 
16
16
  const CaptionViewer = function($container, api, playerState){
17
- const $root = LA$("#"+api.getContainerId());
17
+ const $root = LA$(api.getContainerElement());
18
18
 
19
19
  const onRendered = function($container, $current, template){
20
20
  let isDisable = false;
@@ -5,7 +5,7 @@ import OvenTemplate from 'view/engine/OvenTemplate';
5
5
  import LA$ from 'utils/likeA$';
6
6
 
7
7
  const ContextPanel = function($container, api, position){
8
- const $root = LA$("#"+api.getContainerId());
8
+ const $root = LA$(api.getContainerElement());
9
9
 
10
10
  const onRendered = function($current, template){
11
11
  const panelWidth = $current.width();
@@ -3,7 +3,7 @@ export default (uiText) => {
3
3
  return (
4
4
  `<div class="op-context-panel animated fadeIn">` +
5
5
  `<div class="op-context-item" tabindex="1">` +
6
- `<span class="op-context-item-text">${uiText.context}</span>` +
6
+ `<span class="op-context-item-text">${uiText.context} ${version}</span>` +
7
7
  `</div>`+
8
8
  `</div>`
9
9
  );
@@ -29,6 +29,7 @@ import {
29
29
  PLAYER_STATE,
30
30
  ALL_PLAYLIST_ENDED,
31
31
  CONTENT_LEVEL_CHANGED,
32
+ CONTENT_SOURCE_CHANGED,
32
33
  NETWORK_UNSTABLED,
33
34
  UI_ICONS
34
35
  } from "api/constants";
@@ -76,9 +77,22 @@ const Helpers = function($container, api){
76
77
  messageBox = MessageBox($current, api, message, description, withTimer, iconClass, clickCallback, dontClose);
77
78
  }
78
79
  function createThumbnail(){
80
+
81
+ const mediaElement = api.getMediaElement();
82
+
83
+ if (mediaElement) {
84
+ mediaElement.poster = ''
85
+ }
86
+
87
+ if (api.getConfig().image) {
88
+ mediaElement.poster = api.getConfig().image;
89
+ }
90
+
91
+
79
92
  if(thumbnail){
80
93
  thumbnail.destroy();
81
94
  }
95
+
82
96
  thumbnail = Thumbnail($current, api, api.getConfig());
83
97
  }
84
98
  function createWaterMark() {
@@ -188,6 +202,13 @@ const Helpers = function($container, api){
188
202
  }
189
203
  }, template);
190
204
 
205
+ api.on(CONTENT_SOURCE_CHANGED, function () {
206
+
207
+ if(hasThumbnail){
208
+ createThumbnail(); //shows when playlist changed.
209
+ }
210
+ });
211
+
191
212
  //show spinner cuz dashjs spends long time for level change.
192
213
  api.on(CONTENT_LEVEL_CHANGED, function(data){
193
214
  if(data.currentQuality < 0 ){
@@ -1,6 +1,5 @@
1
1
  export default (uiText, data) => {
2
2
  return (`<div class="op-thumbnail-container"><div class="op-thumbnail-wrapper">`+
3
- `${data.image ? `<img src="${data.image}">`:``}` +
4
3
  `${data.title ? `<div class="op-thumbnail-header">${data.title}</div>`:``}` +
5
4
  `</div></div>`);
6
5
  };
@@ -25,6 +25,7 @@ import PanelsTemplate from 'view/components/controls/settingPanel/mainTemplate';
25
25
  import SpeedPanelTemplate from 'view/components/controls/settingPanel/mainTemplate';
26
26
  import SourcePanelTemplate from 'view/components/controls/settingPanel/mainTemplate';
27
27
  import QualityPanelTemplate from 'view/components/controls/settingPanel/mainTemplate';
28
+ import AudioTrackPanelTemplate from 'view/components/controls/settingPanel/mainTemplate';
28
29
  import CaptionPanelTemplate from 'view/components/controls/settingPanel/mainTemplate';
29
30
  import TimeDisplayPanelTemplate from 'view/components/controls/settingPanel/mainTemplate';
30
31
  import PlaylistPanelTemplate from 'view/components/controls/playlistPanelTemplate';
@@ -53,6 +54,7 @@ const Templates = {
53
54
  SpeedPanelTemplate,
54
55
  SourcePanelTemplate,
55
56
  QualityPanelTemplate,
57
+ AudioTrackPanelTemplate,
56
58
  CaptionPanelTemplate,
57
59
  TimeDisplayPanelTemplate,
58
60
  PlaylistPanelTemplate