ravnur-player-public 3.4.2 → 3.4.4

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 (262) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.js +206 -0
  3. package/.flowconfig +3 -0
  4. package/.vscode/extensions.json +7 -0
  5. package/.vscode/launch.json +37 -0
  6. package/.vscode/settings.json +4 -0
  7. package/README-Private.md +54 -0
  8. package/babel.config.js +28 -0
  9. package/bitbucket-pipelines.yml +61 -0
  10. package/cert.pem +23 -0
  11. package/demo/BaseM.mp4 +0 -0
  12. package/demo/HD.mp4 +0 -0
  13. package/demo/annotations.json +50 -0
  14. package/demo/annotations_ge.json +50 -0
  15. package/demo/base.mp3 +0 -0
  16. package/demo/cc_2125en.vtt +4958 -0
  17. package/demo/cc_en.vtt +171 -0
  18. package/demo/cc_ge.vtt +178 -0
  19. package/demo/chapters_en.vtt +38 -0
  20. package/demo/chapters_ge.vtt +5 -0
  21. package/demo/chapters_ge1.json +23 -0
  22. package/demo/hls/audio/stereo/en/128kbit.m3u8 +912 -0
  23. package/demo/hls/audio/stereo/none/128kbit.m3u8 +912 -0
  24. package/demo/hls/audio/surround/en/320kbit.m3u8 +912 -0
  25. package/demo/hls/playlist.m3u8 +31 -0
  26. package/demo/hls/video/10000kbit.m3u8 +894 -0
  27. package/demo/hls/video/1100kbit.m3u8 +894 -0
  28. package/demo/hls/video/1500kbit.m3u8 +894 -0
  29. package/demo/hls/video/250kbit.m3u8 +894 -0
  30. package/demo/hls/video/4000kbit.m3u8 +894 -0
  31. package/demo/hls/video/500kbit.m3u8 +894 -0
  32. package/demo/hls/video/6000kbit.m3u8 +894 -0
  33. package/demo/hls/video/800kbit.m3u8 +894 -0
  34. package/demo/hls.js +5 -0
  35. package/demo/hls.js.map +1 -0
  36. package/demo/hls.min.js +2 -0
  37. package/demo/hls.min.js.map +1 -0
  38. package/demo/playlist.m3u8 +31 -0
  39. package/demo/ravnur-flash-audio.swf +0 -0
  40. package/demo/ravnur-flash-video-hls.swf +0 -0
  41. package/demo/ravnur-flash-video.swf +0 -0
  42. package/demo/shaka/shaka-player.foo.debug.d.ts +4532 -0
  43. package/demo/shaka/shaka-player.foo.debug.externs.js +3886 -0
  44. package/demo/shaka/shaka-player.foo.debug.js +1746 -0
  45. package/demo/shaka/shaka-player.foo.debug.map +8 -0
  46. package/demo/shaka/wrapper.js +7 -0
  47. package/demo/test.html +458 -0
  48. package/dist/RavnurMediaPlayer.min.js +1 -1
  49. package/dist/cdn/RavnurMediaPlayer.min.js +1 -1
  50. package/jest.config.js +4 -0
  51. package/key.pem +27 -0
  52. package/lib/es5.js +344 -0
  53. package/lib/images/Spinner-small.gif +0 -0
  54. package/lib/images/close.png +0 -0
  55. package/lib/images/ic_check_box_black_24dp_1x.png +0 -0
  56. package/lib/images/ic_check_box_outline_blank_black_24dp_1x.png +0 -0
  57. package/lib/images/ic_chevron_left_white_24dp_1x.png +0 -0
  58. package/lib/images/ic_chevron_right_white_24dp_1x.png +0 -0
  59. package/lib/images/ic_closed_caption_white_24dp_1x.png +0 -0
  60. package/lib/images/ic_fast_forward_white_24dp_1x.png +0 -0
  61. package/lib/images/ic_fast_rewind_white_24dp_1x.png +0 -0
  62. package/lib/images/ic_fullscreen_exit_white_24dp_1x.png +0 -0
  63. package/lib/images/ic_fullscreen_white_24dp_1x.png +0 -0
  64. package/lib/images/ic_hd_white_24dp_1x.png +0 -0
  65. package/lib/images/ic_keyboard_arrow_left_black_24dp_1x.png +0 -0
  66. package/lib/images/ic_keyboard_arrow_right_black_24dp_1x.png +0 -0
  67. package/lib/images/ic_pause_white_24dp_1x.png +0 -0
  68. package/lib/images/ic_photo_white_24dp_1x.png +0 -0
  69. package/lib/images/ic_play_arrow_white_24dp_1x.png +0 -0
  70. package/lib/images/ic_refresh_white_24dp_1x.png +0 -0
  71. package/lib/images/ic_settings_white_24dp_1x.png +0 -0
  72. package/lib/images/ic_skip_next_white_24dp_1x.png +0 -0
  73. package/lib/images/ic_skip_previous_white_24dp_1x.png +0 -0
  74. package/lib/images/ic_toc_white_24dp_1x.png +0 -0
  75. package/lib/images/ic_volume_off_white_24dp_1x.png +0 -0
  76. package/lib/images/ic_volume_up_white_24dp_1x.png +0 -0
  77. package/lib/player4ie8.css +225 -0
  78. package/package.json +1 -5
  79. package/server.js +29 -0
  80. package/src/config/cc.js +56 -0
  81. package/src/config/i18n.js +101 -0
  82. package/src/config/options.js +123 -0
  83. package/src/config/playlist.js +9 -0
  84. package/src/config/source.js +23 -0
  85. package/src/config/statuses.js +8 -0
  86. package/src/config/styles.js +16 -0
  87. package/src/entity.js +27 -0
  88. package/src/events.js +5 -0
  89. package/src/extensions/annotations.js +142 -0
  90. package/src/extensions/audio-tarcks.js +115 -0
  91. package/src/extensions/backward.js +45 -0
  92. package/src/extensions/base.js +73 -0
  93. package/src/extensions/bottom-next.js +50 -0
  94. package/src/extensions/bottom-prev.js +50 -0
  95. package/src/extensions/buffering.js +78 -0
  96. package/src/extensions/c2pa.js +350 -0
  97. package/src/extensions/caption-search.js +230 -0
  98. package/src/extensions/cc.js +874 -0
  99. package/src/extensions/crawl.js +118 -0
  100. package/src/extensions/download.js +411 -0
  101. package/src/extensions/error.js +47 -0
  102. package/src/extensions/forward.js +44 -0
  103. package/src/extensions/fullscreen.js +84 -0
  104. package/src/extensions/help.js +201 -0
  105. package/src/extensions/helpers/FileSaver.js +157 -0
  106. package/src/extensions/helpers/clickOpener.js +180 -0
  107. package/src/extensions/helpers/opener.js +30 -0
  108. package/src/extensions/helpers/openerHeightChecker.js +13 -0
  109. package/src/extensions/helpers/popover.js +33 -0
  110. package/src/extensions/helpers/popoverPosition.js +30 -0
  111. package/src/extensions/helpers/scrollIntoView.js +9 -0
  112. package/src/extensions/helpers/storage.js +20 -0
  113. package/src/extensions/helpers/textContent.js +6 -0
  114. package/src/extensions/helpers/timeCodeToSeconds.js +44 -0
  115. package/src/extensions/helpers/transport.js +43 -0
  116. package/src/extensions/helpers/vtt-loader.js +42 -0
  117. package/src/extensions/index.js +87 -0
  118. package/src/extensions/live.js +76 -0
  119. package/src/extensions/mux.js +57 -0
  120. package/src/extensions/next-frame.js +44 -0
  121. package/src/extensions/next.js +48 -0
  122. package/src/extensions/placeholder.js +241 -0
  123. package/src/extensions/play.js +102 -0
  124. package/src/extensions/poster.js +47 -0
  125. package/src/extensions/prev-frame.js +44 -0
  126. package/src/extensions/prev.js +48 -0
  127. package/src/extensions/progress.js +465 -0
  128. package/src/extensions/resizer.js +37 -0
  129. package/src/extensions/settings.js +367 -0
  130. package/src/extensions/theater.js +56 -0
  131. package/src/extensions/title.js +38 -0
  132. package/src/extensions/toc.js +334 -0
  133. package/src/extensions/volume.js +196 -0
  134. package/src/flash/FlashPlugin.js +301 -0
  135. package/src/flash/MediaElement.js +361 -0
  136. package/src/flash/plugins.js +32 -0
  137. package/src/flash-detector.js +66 -0
  138. package/src/helpers/$t.js +10 -0
  139. package/src/helpers/binder.js +11 -0
  140. package/src/helpers/isAndroid.js +5 -0
  141. package/src/helpers/isBlackBerry.js +5 -0
  142. package/src/helpers/isCanvasSupported.js +6 -0
  143. package/src/helpers/isIE.js +21 -0
  144. package/src/helpers/isMobile.js +10 -0
  145. package/src/helpers/isWindows.js +5 -0
  146. package/src/helpers/isWindowsPhone.js +5 -0
  147. package/src/helpers/isiOS.js +5 -0
  148. package/src/html5media.js +19 -0
  149. package/src/index.js +2 -0
  150. package/src/logger.js +31 -0
  151. package/src/microevent.js +65 -0
  152. package/src/normalize-options.js +139 -0
  153. package/src/player.js +864 -0
  154. package/src/players/base.js +209 -0
  155. package/src/players/flash.js +172 -0
  156. package/src/players/hls.js +278 -0
  157. package/src/players/html.js +205 -0
  158. package/src/players/index.js +59 -0
  159. package/src/players/shaka.js +219 -0
  160. package/src/playlist.js +362 -0
  161. package/src/screenfull.js +121 -0
  162. package/src/state.js +474 -0
  163. package/src/static/es5.js +344 -0
  164. package/src/static/images/Spinner-small.gif +0 -0
  165. package/src/static/images/close.png +0 -0
  166. package/src/static/images/ic_check_box_black_24dp_1x.png +0 -0
  167. package/src/static/images/ic_check_box_outline_blank_black_24dp_1x.png +0 -0
  168. package/src/static/images/ic_chevron_left_white_24dp_1x.png +0 -0
  169. package/src/static/images/ic_chevron_right_white_24dp_1x.png +0 -0
  170. package/src/static/images/ic_closed_caption_white_24dp_1x.png +0 -0
  171. package/src/static/images/ic_fast_forward_white_24dp_1x.png +0 -0
  172. package/src/static/images/ic_fast_rewind_white_24dp_1x.png +0 -0
  173. package/src/static/images/ic_fullscreen_exit_white_24dp_1x.png +0 -0
  174. package/src/static/images/ic_fullscreen_white_24dp_1x.png +0 -0
  175. package/src/static/images/ic_hd_white_24dp_1x.png +0 -0
  176. package/src/static/images/ic_keyboard_arrow_left_black_24dp_1x.png +0 -0
  177. package/src/static/images/ic_keyboard_arrow_right_black_24dp_1x.png +0 -0
  178. package/src/static/images/ic_pause_white_24dp_1x.png +0 -0
  179. package/src/static/images/ic_play_arrow_white_24dp_1x.png +0 -0
  180. package/src/static/images/ic_refresh_white_24dp_1x.png +0 -0
  181. package/src/static/images/ic_settings_white_24dp_1x.png +0 -0
  182. package/src/static/images/ic_skip_next_white_24dp_1x.png +0 -0
  183. package/src/static/images/ic_skip_previous_white_24dp_1x.png +0 -0
  184. package/src/static/images/ic_toc_white_24dp_1x.png +0 -0
  185. package/src/static/images/ic_volume_off_white_24dp_1x.png +0 -0
  186. package/src/static/images/ic_volume_up_white_24dp_1x.png +0 -0
  187. package/src/static/player4ie8.css +225 -0
  188. package/src/styles/bplaylist.css.js +124 -0
  189. package/src/styles/index.js +1966 -0
  190. package/src/styles/playlist.css.js +84 -0
  191. package/src/styles/rplaylist.css.js +98 -0
  192. package/src/svgs.js +111 -0
  193. package/src/types/Logger.js +10 -0
  194. package/src/types/Options.js +179 -0
  195. package/src/types/Playlist.js +3 -0
  196. package/src/types/Source.js +28 -0
  197. package/src/types/State.js +46 -0
  198. package/src/types/Styles.js +11 -0
  199. package/src/types/TimeData.js +8 -0
  200. package/src/types/Translation.js +69 -0
  201. package/src/utils/absolutizeUrl.js +9 -0
  202. package/src/utils/addClass.js +9 -0
  203. package/src/utils/addEvent.js +31 -0
  204. package/src/utils/addProperty.js +65 -0
  205. package/src/utils/appendChild.js +14 -0
  206. package/src/utils/buff2hex.js +5 -0
  207. package/src/utils/contains.js +33 -0
  208. package/src/utils/createElement.js +24 -0
  209. package/src/utils/each.js +34 -0
  210. package/src/utils/escapeHTML.js +8 -0
  211. package/src/utils/existy.js +4 -0
  212. package/src/utils/extend.js +17 -0
  213. package/src/utils/filter.js +16 -0
  214. package/src/utils/find.js +11 -0
  215. package/src/utils/findIndex.js +20 -0
  216. package/src/utils/first.js +5 -0
  217. package/src/utils/get.js +19 -0
  218. package/src/utils/has.js +5 -0
  219. package/src/utils/hasClass.js +6 -0
  220. package/src/utils/head.js +11 -0
  221. package/src/utils/inRange.js +16 -0
  222. package/src/utils/index.js +73 -0
  223. package/src/utils/isArray.js +4 -0
  224. package/src/utils/isBoolean.js +3 -0
  225. package/src/utils/isElement.js +7 -0
  226. package/src/utils/isEmpty.js +6 -0
  227. package/src/utils/isEqual.js +33 -0
  228. package/src/utils/isEqualBuffer.js +13 -0
  229. package/src/utils/isFunction.js +3 -0
  230. package/src/utils/isNotEmpty.js +5 -0
  231. package/src/utils/isObject.js +5 -0
  232. package/src/utils/isString.js +9 -0
  233. package/src/utils/last.js +4 -0
  234. package/src/utils/map.js +11 -0
  235. package/src/utils/negate.js +8 -0
  236. package/src/utils/noop.js +1 -0
  237. package/src/utils/notExisty.js +5 -0
  238. package/src/utils/reduce.js +8 -0
  239. package/src/utils/remove.js +7 -0
  240. package/src/utils/removeClass.js +8 -0
  241. package/src/utils/removeEvent.js +7 -0
  242. package/src/utils/toArray.js +7 -0
  243. package/src/utils/toggleClass.js +16 -0
  244. package/src/utils/uidGenerator.js +8 -0
  245. package/src/utils/upperFirst.js +4 -0
  246. package/tests/extensions/__snapshots__/download.spec.js.snap +226 -0
  247. package/tests/extensions/__snapshots__/fullscreen.spec.js.snap +30 -0
  248. package/tests/extensions/__snapshots__/title.spec.js.snap +16 -0
  249. package/tests/extensions/download.spec.js +111 -0
  250. package/tests/extensions/fullscreen.spec.js +56 -0
  251. package/tests/extensions/title.spec.js +35 -0
  252. package/tests/mocks/assets/BaseM.mp4 +0 -0
  253. package/tests/mocks/assets/hls.min.js +5 -0
  254. package/tests/mocks/assets/styleMock.js +1 -0
  255. package/tests/mocks/base-player-options.js +47 -0
  256. package/tests/mocks/sources.js +58 -0
  257. package/tests/mocks/timedata/cc_en.vtt +171 -0
  258. package/tests/mocks/timedata/cc_ge.vtt +178 -0
  259. package/tests/utils/wait.js +1 -0
  260. package/webpack.config.js +78 -0
  261. package/dist/.DS_Store +0 -0
  262. package/dist/cdn/.DS_Store +0 -0
package/src/player.js ADDED
@@ -0,0 +1,864 @@
1
+ // @flow
2
+ import createPlayer from './players';
3
+ import { isHLS } from './players';
4
+ import screenfull from './screenfull';
5
+ import extensions from './extensions';
6
+ import appendStyles from './styles';
7
+ import Playlist from './playlist';
8
+ import Entity from './entity';
9
+ import MicroEvent from './microevent';
10
+
11
+ import hasFlashPlayer from './flash-detector';
12
+
13
+ import BaseController from './players/base';
14
+ import BaseExtension from './extensions/base';
15
+
16
+ import createLogger from './logger';
17
+ import normalizeOptions from './normalize-options';
18
+
19
+ import $t from './helpers/$t';
20
+ import binder from './helpers/binder';
21
+
22
+ import {
23
+ isElement, append, extend, each, createElement, existy, addClass, removeClass, toggleClass,
24
+ contains, isArray, head, findIndex, get, hasClass
25
+ } from './utils';
26
+
27
+ import DEFAULT_OPTIONS from './config/options';
28
+ import DEFAULT_STYLES from './config/styles';
29
+ import { PLAYLIST_MODES, BOTTOM_MODE, RIGHT_MODE, AUTO_MODE } from './config/playlist';
30
+
31
+ import isMobile from './helpers/isMobile';
32
+ import isiOS from './helpers/isiOS';
33
+ import isIE, { isIE8, isIE11 } from './helpers/isIE';
34
+
35
+ import StateEntity from './state';
36
+
37
+ import type { Player$Logger } from './types/Logger';
38
+ import type { Player$Styles } from './types/Styles';
39
+ import type { Player$Source } from './types/Source';
40
+ import type { Player$PlaylistMode } from './types/Playlist';
41
+ import type { Player$InputOptions, Player$CombineOptions } from './types/Options';
42
+ import type { Player$State, Player$CCLocation, Player$CCFontSize } from './types/State';
43
+ import type { Level } from './logger';
44
+ import type { Player$CrawlOptions } from './config/options';
45
+ import { getStoredData, storeData } from './extensions/helpers/storage';
46
+ import CrawlExtension from './extensions/crawl';
47
+
48
+ const CN = 'rplayer';
49
+ const FULLSCREEN_CN = `${CN}--fullscreen`;
50
+ const IPHONE_CN = `${CN}--iphone`;
51
+ const MOBILE_CN = `${CN}--mobile`;
52
+ const EL_BELOW_CC_75_CN = `${CN}--cc-75-below`;
53
+ const EL_BELOW_CC_100_CN = `${CN}--cc-100-below`;
54
+ const EL_BELOW_CC_125_CN = `${CN}--cc-125-below`;
55
+ const EL_BELOW_CC_150_CN = `${CN}--cc-150-below`;
56
+ const EL_BELOW_CC_200_CN = `${CN}--cc-200-below`;
57
+
58
+ const INNER_CN = `${CN}__inner`;
59
+ const INNER_PLAYING_CN = `${INNER_CN}--playing`;
60
+ const INNER_ACTIVE_CN = `${INNER_CN}--active`;
61
+ const INNER_HOVER_CN = `${INNER_CN}--hovering`;
62
+ const INNER_LIGHT_CN = `${INNER_CN}--light`;
63
+ const INNER_BELOW_CC_CN = `${INNER_CN}--cc-below`;
64
+ const INNER_ACCESSABILITY_CN = `${INNER_CN}--accessibility`;
65
+
66
+ const EXTENSIONS_CN = 'rmp-extensions';
67
+ const EXTENSIONS_HIDDEN_CN = `${EXTENSIONS_CN}--hidden`;
68
+ const EXTENSION_CRAWL_CN = 'rmp-ext-crawl';
69
+ const EXTENSION_CRAWL_VISIBLE_CN = `${EXTENSION_CRAWL_CN}--exist`;
70
+
71
+ const SAVE_PLAY_TIME_KEY = 'last-play-time';
72
+ const SAVE_PLAY_TIME_LAST_TIME = 10; // 10 seconds
73
+ const SAVE_PLAY_TIME_SKIP = 5; // 5 seconds
74
+
75
+ let hasAddedStyles = false;
76
+ let accessibility = false;
77
+ let inactivityTimer = 0;
78
+ let intervalId;
79
+
80
+ const PLAYLIST_MODES_CN: { [key: Player$PlaylistMode]: string } = {
81
+ [BOTTOM_MODE] : `${CN}--bottom-playlist`,
82
+ [RIGHT_MODE] : `${CN}--right-playlist`
83
+ };
84
+
85
+ const TAB_KEY = 9;
86
+
87
+ export default class Player extends Entity {
88
+ controller: ?BaseController = null
89
+ extensions: BaseExtension[] = []
90
+ state: StateEntity
91
+ _playlist: Player$Source[] = []
92
+
93
+ originOptions: ?Player$InputOptions = null
94
+ options: ?Player$CombineOptions = null
95
+ activeSourceId: string;
96
+
97
+ $el: HTMLElement
98
+ $inner: HTMLElement
99
+ $extensionsWrapper: ?HTMLElement = null
100
+
101
+ playlistController: ?Playlist = null
102
+
103
+ _timerId: ?TimeoutID = null
104
+ _isOpenPopup: boolean = false
105
+ _clipStopInterval: ?IntervalID = null
106
+ _isPlaylist: boolean = false
107
+
108
+ constructor(el: HTMLElement, styles?: $Shape<Player$Styles> = {}, logger?: Player$Logger = createLogger()) {
109
+ super(new MicroEvent(), logger);
110
+
111
+ if (!hasAddedStyles) {
112
+ styles = extend({}, DEFAULT_STYLES, styles);
113
+ appendStyles(styles, isIE8() ? el.getBoundingClientRect() : null);
114
+ hasAddedStyles = true;
115
+ }
116
+
117
+ const parent = el;
118
+ this.$el = createElement('div', { class: CN }, parent);
119
+
120
+ toggleClass(this.$el, IPHONE_CN, isiOS());
121
+ toggleClass(this.$el, MOBILE_CN, isMobile());
122
+
123
+ this.$inner = createElement('div', { class: INNER_CN }, this.$el);
124
+
125
+ binder(this, [ 'onStateChanged', 'onFullScreenChanged', 'disappearExtensions',
126
+ 'appearExtensions', '_renderPlayer', 'onPlay', 'onPause', 'onMouseMove', 'onClick',
127
+ '_disappearExtensionsDelayed', '_appearExtensionsImmediately', 'onOpenPopup', 'onClosePopup',
128
+ 'onPlayClicked', 'onChangePlaylistMode', 'onMouseEnter', 'onMouseLeave', 'onKeydown', 'onMobileTouch',
129
+ '_heartbeatExtension', '_handleQualityChange', 'onTimeUpdate', '_handleLastPlayTime']);
130
+
131
+ this.bus.on('statechanged', this.onStateChanged);
132
+ this.bus.on('pause', this.onPause);
133
+ this.bus.on('timeupdate', this.onTimeUpdate);
134
+ this.bus.on('ended', this.onPause);
135
+ this.bus.on('play', this.onPlay);
136
+ this.bus.on('changesource', this._renderPlayer );
137
+ this.bus.on('showpopup', this.onOpenPopup);
138
+ this.bus.on('hidepopup', this.onClosePopup);
139
+ this.bus.on('handle-play-clicked', this.onPlayClicked);
140
+ this.bus.on('changeplaylistmode', this.onChangePlaylistMode);
141
+ this.bus.on('heartbeatextensions', this._heartbeatExtension);
142
+ this.bus.on('manualquality', this._handleQualityChange);
143
+
144
+ this.state = new StateEntity(this.bus, logger);
145
+
146
+ if ( isMobile() ) {
147
+ this.bus.on('mobiletouch', this.onMobileTouch);
148
+ } else {
149
+ this.addEvent(this.$el, 'mouseleave', this.onMouseLeave);
150
+ this.addEvent(this.$el, 'mouseenter', this.onMouseEnter);
151
+ this.addEvent(this.$el, 'mousemove', this.onMouseMove);
152
+ this.addEvent(this.$el, 'keydown', this.onKeydown);
153
+ this.addEvent(this.$el, 'click', this.onClick);
154
+ }
155
+
156
+ if (screenfull.enabled) {
157
+ this.$el.addEventListener('webkitfullscreenchange', this.onFullScreenChanged);
158
+ this.$el.addEventListener('fullscreenchange', this.onFullScreenChanged);
159
+ document.addEventListener('mozfullscreenchange', this.onFullScreenChanged);
160
+ document.addEventListener('MSFullscreenChange', this.onFullScreenChanged);
161
+ }
162
+ }
163
+
164
+ onMouseLeave() {
165
+ removeClass(this.$inner, INNER_HOVER_CN);
166
+ this.disappearExtensions();
167
+ }
168
+
169
+ onMouseEnter() {
170
+ addClass(this.$inner, INNER_HOVER_CN);
171
+ this.appearExtensions();
172
+ }
173
+
174
+ onKeydown(e: KeyboardEvent) {
175
+ if (!accessibility) return;
176
+ clearInterval(intervalId);
177
+ inactivityTimer = 0;
178
+
179
+ const keyCode = e.keyCode;
180
+
181
+ if (keyCode === TAB_KEY) {
182
+ this.appearExtensions();
183
+ }
184
+
185
+ intervalId = setInterval(() => {
186
+ inactivityTimer++;
187
+ if (inactivityTimer > 5) {
188
+ inactivityTimer = 0;
189
+ this.disappearExtensions();
190
+ clearInterval(intervalId);
191
+ }
192
+ }, 1000);
193
+ }
194
+
195
+ onPlay() {
196
+ addClass(this.$inner, INNER_PLAYING_CN);
197
+ this.onMouseMove();
198
+ }
199
+
200
+ onPause() {
201
+ if (!this.options.playLoop) {
202
+ removeClass(this.$inner, INNER_PLAYING_CN);
203
+ this.appearExtensions();
204
+ }
205
+ }
206
+
207
+ onPlayClicked() {
208
+ removeClass(this.$inner, INNER_LIGHT_CN);
209
+ }
210
+
211
+ onTimeUpdate() {
212
+ const { activeSourceId, controller } = this;
213
+ const { savePlayTime } = this.originOptions;
214
+ const ignoreSaveTime = controller.getDuration() <= (SAVE_PLAY_TIME_LAST_TIME + SAVE_PLAY_TIME_SKIP);
215
+ let time = controller.getCurrentTime();
216
+
217
+ if (time < SAVE_PLAY_TIME_SKIP || ignoreSaveTime) {
218
+ return;
219
+ }
220
+
221
+ if (!savePlayTime || !activeSourceId) {
222
+ return;
223
+ }
224
+
225
+ let existed = getStoredData(SAVE_PLAY_TIME_KEY) || '{}';
226
+ existed = JSON.parse(existed);
227
+
228
+ if (!existed.expires) {
229
+ let expires = new Date();
230
+ existed.expires = new Date().setMonth(expires.getMonth() + 1);
231
+ }
232
+
233
+ if (new Date().getTime() > existed.expires) {
234
+ existed = {};
235
+ existed.expires = new Date().setMonth(new Date().getMonth() + 1);
236
+ }
237
+
238
+ const lastAvailableTime = controller.getDuration() - SAVE_PLAY_TIME_LAST_TIME;
239
+ time = time <= lastAvailableTime ? time : lastAvailableTime;
240
+
241
+ existed[activeSourceId] = time;
242
+
243
+ storeData(SAVE_PLAY_TIME_KEY, JSON.stringify(existed));
244
+ }
245
+
246
+ isShownExtensions() {
247
+ const { $extensionsWrapper } = this;
248
+
249
+ if (!$extensionsWrapper) {
250
+ return false;
251
+ }
252
+
253
+ let res = !hasClass(this.$inner, EXTENSIONS_HIDDEN_CN);
254
+ res = res || hasClass(this.$inner, INNER_LIGHT_CN);
255
+ // res = res || hasClass(this.$inner, INNER_HOVER_CN);
256
+ return res;
257
+ }
258
+
259
+ onMobileTouch() {
260
+ const { controller } = this;
261
+ if ( controller && this.isShownExtensions() ) {
262
+ if ( controller.isPaused() ) {
263
+ controller.play();
264
+ } else {
265
+ controller.pause();
266
+ }
267
+ }
268
+ this._heartbeatExtension();
269
+ }
270
+
271
+ onMouseMove() {
272
+ this._heartbeatExtension();
273
+ }
274
+
275
+ onClick() {
276
+ this._heartbeatExtension();
277
+ }
278
+
279
+ _heartbeatExtension() {
280
+ this._appearExtensionsImmediately();
281
+
282
+ if (!this._isOpenPopup) {
283
+ this._disappearExtensionsDelayed();
284
+ }
285
+ }
286
+
287
+ onOpenPopup() {
288
+ this._isOpenPopup = true;
289
+ addClass(this.$inner, INNER_ACTIVE_CN);
290
+ this._appearExtensionsImmediately();
291
+ }
292
+
293
+ onClosePopup() {
294
+ this._isOpenPopup = false;
295
+ removeClass(this.$inner, INNER_ACTIVE_CN);
296
+ this._disappearExtensionsDelayed();
297
+ }
298
+
299
+ _appearExtensionsImmediately() {
300
+ this.appearExtensions();
301
+ if (this._timerId) {
302
+ clearTimeout(this._timerId);
303
+ }
304
+ }
305
+
306
+ _disappearExtensionsDelayed() {
307
+ const { originOptions } = this;
308
+ if (!originOptions || originOptions.alwaysShowExtensions) {
309
+ return;
310
+ }
311
+ this._timerId = setTimeout(this.disappearExtensions, originOptions.extensionsVisibilityTimeout);
312
+ }
313
+
314
+ _getParentElementForController(): ?HTMLElement {
315
+ const { controller } = this;
316
+ if (!controller) {
317
+ return null;
318
+ }
319
+
320
+ const $el = controller.getElement();
321
+ if (!$el) {
322
+ return null;
323
+ }
324
+
325
+ const parent = $el.parentNode;
326
+ if (parent && parent instanceof HTMLElement) {
327
+ return parent;
328
+ }
329
+
330
+ return null;
331
+ }
332
+
333
+ changeFullScreenMode() {
334
+ const parent = this._getParentElementForController();
335
+ if (!parent && !isiOS()) {
336
+ return;
337
+ }
338
+
339
+ const isFullScreenMode = this.state.isFullScreen();
340
+
341
+ // if ( isFullScreenMode) {
342
+ // if (!screenfull.enabled) {
343
+ // _setFullSize(parent);
344
+ // }
345
+
346
+ // return;
347
+ // }
348
+
349
+ this.$inner.style.width = '';
350
+ this.$inner.style.height = '';
351
+
352
+ if (screenfull.enabled) {
353
+ if (isFullScreenMode) {
354
+ screenfull.request(this.$el);
355
+ } else {
356
+ screenfull.exit();
357
+ }
358
+ } else if (isiOS() && this.controller) {
359
+ // $FlowFixMe
360
+ this.controller.getElement().webkitEnterFullscreen();
361
+ this.bus.emit('fullscreenchanging', false);
362
+ } else {
363
+ const parent = this.$el.parentNode;
364
+ if (!parent || !( parent instanceof HTMLElement )) {
365
+ return;
366
+ }
367
+
368
+ if (isFullScreenMode) {
369
+ addClass(parent, FULLSCREEN_CN);
370
+ _setFullSize(parent);
371
+ } else {
372
+ removeClass(parent, FULLSCREEN_CN);
373
+ _clearSize(parent);
374
+ }
375
+ this.bus.emit('fullscreenchanged', isFullScreenMode);
376
+ }
377
+ }
378
+
379
+ onStateChanged(state: Player$State, old: Player$State) {
380
+ if (state.isFullScreen !== old.isFullScreen) {
381
+ this.changeFullScreenMode();
382
+ }
383
+ if ( state.cc.fontSize !== old.cc.fontSize ||
384
+ state.cc.location !== old.cc.location ||
385
+ state.cc.lang !== old.cc.lang
386
+ ) {
387
+
388
+ const lang = state.cc.lang;
389
+ if (lang) {
390
+ this.changeLayout(lang, state.cc.fontSize, state.cc.location);
391
+ }
392
+ }
393
+ }
394
+
395
+ onFullScreenChanged() {
396
+ const isFullScreen = screenfull.isFullscreen;
397
+ this.bus.emit('fullscreenchanging', isFullScreen);
398
+ const parent = this.$el.parentNode;
399
+ if (!parent || !( parent instanceof HTMLElement )) {
400
+ return;
401
+ }
402
+
403
+ toggleClass(parent, FULLSCREEN_CN, screenfull.isFullscreen);
404
+ }
405
+
406
+ changeLayout(lang: string, fontSize: Player$CCFontSize, location: Player$CCLocation) {
407
+ const isBelowtMode = lang && location === 'below';
408
+ toggleClass(this.$inner, INNER_BELOW_CC_CN, isBelowtMode);
409
+ toggleClass(this.$el, EL_BELOW_CC_75_CN, isBelowtMode && fontSize === '75%');
410
+ toggleClass(this.$el, EL_BELOW_CC_100_CN, isBelowtMode && fontSize === '100%');
411
+ toggleClass(this.$el, EL_BELOW_CC_125_CN, isBelowtMode && fontSize === '125%');
412
+ toggleClass(this.$el, EL_BELOW_CC_150_CN, isBelowtMode && fontSize === '150%');
413
+ toggleClass(this.$el, EL_BELOW_CC_200_CN, isBelowtMode && fontSize === '200%');
414
+ }
415
+
416
+ _detectPlaylistMode(): Player$PlaylistMode {
417
+ const { originOptions } = this;
418
+ if (!originOptions) {
419
+ return 'auto';
420
+ }
421
+ let mode = originOptions.playlistmode;
422
+ mode = contains(PLAYLIST_MODES, mode) ? mode : head(PLAYLIST_MODES);
423
+ if ( mode === AUTO_MODE ) {
424
+ mode = isMobile() ? BOTTOM_MODE : RIGHT_MODE;
425
+ }
426
+ return mode;
427
+ }
428
+
429
+ setup(playlist: Player$Source | Player$Source[], options?: $Shape<Player$InputOptions> = {}) {
430
+ // $FlowFixMe
431
+ const level: Level = existy(options.loggerLevel) ? options.loggerLevel : DEFAULT_OPTIONS.loggerLevel;
432
+ const logger = options.logger || createLogger(level);
433
+ const o = { bus: this.bus, logger: options.logger || logger };
434
+ const originOptions: Player$InputOptions = extend(o, DEFAULT_OPTIONS, options);
435
+
436
+ accessibility = options.accessibility;
437
+
438
+ // Accessability: always keep controls visible
439
+ if (accessibility) {
440
+ addClass(this.$inner, INNER_ACCESSABILITY_CN);
441
+ }
442
+
443
+ this.originOptions = originOptions;
444
+
445
+ this._isPlaylist = isArray(playlist);
446
+ this._playlist = [].concat(playlist);
447
+
448
+ if ( !this._playlist.length ) {
449
+ setTimeout(() => {
450
+ const parent = this.$el.parentNode;
451
+ if (parent && parent instanceof HTMLElement) {
452
+ parent.style.position = 'relative';
453
+ parent.style.border = '1px solid grey';
454
+ }
455
+ this.destroy();
456
+ const h1 = createElement('i', { class: 'rmp-no-video' }, parent);
457
+ h1.textContent = $t(originOptions.i18n, 'no-video');
458
+ }, 5);
459
+ return;
460
+ }
461
+
462
+ if (this._isPlaylist) {
463
+ const mode = this._detectPlaylistMode();
464
+ this.onChangePlaylistMode(mode);
465
+ const label = $t(originOptions.i18n, 'playlist-count-of');
466
+ const title = originOptions.playlistitle;
467
+ const forcePoint = originOptions.playlistforcepoint;
468
+ const loop = originOptions.playLoop;
469
+ const opts = { mode, bus: this.bus, title, label, forcePoint, logger, loop };
470
+ this.playlistController = new Playlist(this._playlist, opts);
471
+
472
+ if (!originOptions.hideplaylist) {
473
+ append(this.$el, this.playlistController.getElement());
474
+ }
475
+
476
+ if (originOptions.plalistAutoGoNext) {
477
+ this.bus.on('ended', () => {
478
+ this.bus.emit('nexttrack');
479
+ this._playOnLoad();
480
+ });
481
+ }
482
+ }
483
+
484
+ if (!this._isPlaylist || this.originOptions.hideplaylist) {
485
+ this.bus.emit('changesource', head(this._playlist));
486
+ }
487
+
488
+ this.bus.on('*', e => originOptions.logger.debug(e) );
489
+ const state = this.state;
490
+ const mode = state.getCCLang() && state.getCCLocation() || 'over';
491
+ this._afterSetup();
492
+
493
+ setTimeout(() => {
494
+ this.bus.emit('cclayoutchange', { mode, fontSize: state.getCCFontSize() });
495
+ });
496
+ }
497
+
498
+ onChangePlaylistMode(mode: Player$PlaylistMode) {
499
+ if (!this.originOptions.hideplaylist) {
500
+ each(PLAYLIST_MODES_CN, (cls, key) => toggleClass(this.$el, cls, key === mode) );
501
+ }
502
+ }
503
+
504
+ _runOnce(fnc: () => void) {
505
+ this.bus.once('canplaythrough', () => setTimeout(fnc));
506
+ this.bus.once('loadedmetadata', () => setTimeout(fnc));
507
+ }
508
+
509
+ _playOnLoad() {
510
+ this._runOnce(() => {
511
+ const { controller } = this;
512
+ if (controller) {
513
+ controller.play();
514
+ }
515
+ });
516
+ }
517
+
518
+ _afterSetup() {
519
+ const { controller, originOptions } = this;
520
+ if (!controller || !originOptions) {
521
+ return;
522
+ }
523
+ const { autoStart, startTime, endTime } = originOptions;
524
+
525
+ if (autoStart) {
526
+ this._playOnLoad();
527
+ }
528
+
529
+ if (startTime || endTime) {
530
+ this.playPart(startTime, endTime, true);
531
+ }
532
+ }
533
+
534
+ _handleLastPlayTime() {
535
+ const { savePlayTime, startTime } = this.originOptions;
536
+ const { activeSourceId } = this;
537
+
538
+ if (startTime || !savePlayTime || !activeSourceId) {
539
+ return;
540
+ }
541
+
542
+ let existed = getStoredData(SAVE_PLAY_TIME_KEY);
543
+
544
+ if (!existed) {
545
+ return;
546
+ }
547
+
548
+ existed = JSON.parse(existed);
549
+
550
+ const storedTime = existed[activeSourceId];
551
+
552
+ if (storedTime) {
553
+ this.playPart(storedTime, undefined, true);
554
+ }
555
+ }
556
+
557
+ playPart(from: ?number, to: ?number, lazy: boolean = false) {
558
+ const { controller } = this;
559
+ if (!controller) {
560
+ return;
561
+ }
562
+
563
+ if (typeof from === 'number') {
564
+ if (lazy) {
565
+ const f = from;
566
+ this._runOnce(() => controller.setCurrentTime(f));
567
+ } else {
568
+ controller.setCurrentTime(from);
569
+ }
570
+ }
571
+
572
+ if (typeof to === 'number') {
573
+ const _listener = () => {
574
+ const currentTime = controller.getCurrentTime();
575
+ if (typeof currentTime === 'number' && typeof to === 'number' && currentTime > to) {
576
+ controller.pause();
577
+ this.bus.off('timeupdate', _listener);
578
+ }
579
+ };
580
+ this.bus.on('timeupdate', _listener);
581
+ }
582
+
583
+ if (!lazy) {
584
+ controller.play();
585
+ }
586
+ }
587
+
588
+ // eslint-disable-next-line complexity
589
+ _renderPlayer(source: Player$Source) {
590
+ if ( !source.src ) {
591
+ throw new Error('Incorrent load\'s options.');
592
+ }
593
+
594
+ this.activeSourceId = source.id;
595
+
596
+ const lang = this.state.getCCLang();
597
+ if (lang) {
598
+ this.changeLayout(lang, this.state.getCCFontSize(), this.state.getCCLocation());
599
+ }
600
+
601
+ let playlistMoverOptions = {};
602
+ if (this._isPlaylist && !this.originOptions.hideplaylist) {
603
+ const idx = findIndex(this._playlist, source);
604
+ const next = this._playlist[idx + 1] || null;
605
+ const prev = this._playlist[idx - 1] || null;
606
+ playlistMoverOptions = {
607
+ showNext: existy(next),
608
+ nextTrackThumbnails: get(next, 'poster', ''),
609
+ nextTrackTitle: get(next, 'title', ''),
610
+
611
+ showPrev: existy(prev),
612
+ prevTrackThumbnails: get(prev, 'poster', ''),
613
+ prevTrackTitle: get(prev, 'title', '')
614
+ };
615
+ }
616
+ const options = normalizeOptions(this.originOptions || {}, extend({}, source, playlistMoverOptions));
617
+ this.options = options;
618
+
619
+ if ( this.controller ) {
620
+ this.controller.destroy();
621
+ }
622
+
623
+ this.destroyExtensions();
624
+
625
+ if ( isHLS(options.type) && !Player.canPlayHLS ) {
626
+ const parent = this.$el.parentNode;
627
+ if (parent && parent instanceof HTMLElement) {
628
+ parent.style.position = 'relative';
629
+ parent.style.border = '1px solid grey';
630
+ }
631
+ this.destroy();
632
+ const h1 = createElement('i', { class: 'rmp-no-video' }, parent);
633
+ if (this.originOptions) {
634
+ h1.textContent = $t(this.originOptions.i18n || {}, 'no-flash');
635
+ }
636
+ return;
637
+ }
638
+
639
+ this._beforeRender(options);
640
+
641
+ const controller = createPlayer(options, this.state);
642
+ this.controller = controller;
643
+ append(this.$inner, controller.$el);
644
+
645
+ controller.load(options);
646
+
647
+ this._handleLastPlayTime();
648
+
649
+ if (options.useNativeControls) {
650
+ return;
651
+ }
652
+ removeClass(this.$inner, INNER_PLAYING_CN);
653
+ addClass(this.$inner, INNER_LIGHT_CN);
654
+
655
+ if (options.showCrawl) {
656
+ addClass(this.$inner, EXTENSION_CRAWL_VISIBLE_CN);
657
+ }
658
+
659
+ const $extensionsWrapper = createElement('div', { class: EXTENSIONS_CN }, this.$inner);
660
+ this.$extensionsWrapper = $extensionsWrapper;
661
+
662
+ each(extensions(controller, this.state, options), ext => {
663
+ try {
664
+ const element = ext.getElement();
665
+ if ( element ) {
666
+ append($extensionsWrapper, element);
667
+ ext.addEvent(element, 'dblclick', _stop);
668
+ }
669
+
670
+ const outer = ext.getOuter();
671
+ if ( outer ) {
672
+ append(this.$inner, outer, $extensionsWrapper);
673
+ }
674
+ this.extensions.push(ext);
675
+ } catch (e) {
676
+ options.logger.error(e);
677
+ }
678
+ });
679
+ }
680
+
681
+ _beforeRender({ clip, timecode }: $Shape<Player$CombineOptions>) {
682
+ if (this._clipStopInterval) {
683
+ clearInterval(this._clipStopInterval);
684
+ }
685
+ if ( clip ) {
686
+ const [ start, end ] = clip;
687
+ if (start) {
688
+ this._runOnce(() => {
689
+ if (this.controller) {
690
+ this.controller.setCurrentTime(start);
691
+ }
692
+ });
693
+ }
694
+
695
+ if ( end ) {
696
+ this._clipStopInterval = setInterval(() => {
697
+ const controller = this.controller;
698
+ if ( !controller || controller.isPaused() ) {
699
+ return;
700
+ }
701
+ const currentTime = controller.getCurrentTime();
702
+ if (currentTime > end + timecode) {
703
+ controller.pause();
704
+ setTimeout(() => this.bus.emit('ended'));
705
+ }
706
+ }, 26);
707
+ }
708
+ }
709
+ }
710
+
711
+ _handleQualityChange(quality: mixed) {
712
+ if (this.originOptions) {
713
+ // $FlowFixMe
714
+ this.originOptions.qualityLevel = quality;
715
+ }
716
+ }
717
+
718
+ refreshCrawlExtension(crawl: Player$CrawlOptions, visibility: boolean = true) {
719
+ this.originOptions.logger.debug('crawl:extensions:refreshing');
720
+
721
+ if (!crawl) {
722
+ throw new Error('Crawl options not found');
723
+ }
724
+
725
+ const crawlExtension = this.extensions.find(ext => '$crawl' in ext);
726
+
727
+ if (!crawlExtension) {
728
+ this.originOptions.logger.debug('crawl:extensions:creating');
729
+
730
+ const options = extend({}, this.originOptions, { crawl });
731
+ const extension = new CrawlExtension(this.controller, this.state, options);
732
+ const outer = extension.getOuter();
733
+
734
+ if ( outer ) {
735
+ append(this.$inner, outer, this.$extensionsWrapper);
736
+ }
737
+
738
+ this.extensions.push(extension);
739
+
740
+ return;
741
+ }
742
+
743
+ this.logger.debug('crawl:extensions:refreshing');
744
+
745
+ // $FlowFixMe
746
+ crawlExtension.refresh(crawl, visibility);
747
+ }
748
+
749
+ destroyExtensions() {
750
+ each(this.extensions, ext => ext.destroy());
751
+ this.extensions.length = 0;
752
+
753
+ const { $extensionsWrapper } = this;
754
+
755
+ if ( $extensionsWrapper && isElement($extensionsWrapper) ) {
756
+ const parent = $extensionsWrapper.parentNode;
757
+ if (parent) {
758
+ parent.removeChild($extensionsWrapper);
759
+ }
760
+ }
761
+ }
762
+
763
+ disappearExtensions() {
764
+ const { originOptions, $inner } = this;
765
+
766
+ if (!originOptions || !$inner) {
767
+ return;
768
+ }
769
+
770
+ const showExts = originOptions.alwaysShowExtensions;
771
+ if (this.controller && (showExts || this._isOpenPopup || this.controller.isPaused())) {
772
+ return;
773
+ }
774
+ addClass($inner, EXTENSIONS_HIDDEN_CN);
775
+ }
776
+
777
+ appearExtensions() {
778
+ removeClass(this.$inner, EXTENSIONS_HIDDEN_CN);
779
+ }
780
+
781
+ on(event: string, fnc: (...args: Array<mixed>) => mixed) {
782
+ this.bus.on(event, fnc);
783
+ }
784
+
785
+ off(event: string, fnc: (...args: Array<mixed>) => mixed) {
786
+ this.bus.off(event, fnc);
787
+ }
788
+
789
+ destroy() {
790
+ super.destroy();
791
+ this.bus.destroy();
792
+
793
+ if (this._clipStopInterval) {
794
+ clearInterval(this._clipStopInterval);
795
+ }
796
+
797
+ this.destroyExtensions();
798
+ const { controller } = this;
799
+
800
+ if (controller) {
801
+ controller.pause();
802
+ controller.destroy();
803
+ }
804
+ this.controller = null;
805
+
806
+ if (screenfull.enabled) {
807
+ this.$el.removeEventListener('webkitfullscreenchange', this.onFullScreenChanged);
808
+ this.$el.removeEventListener('fullscreenchange', this.onFullScreenChanged);
809
+ document.removeEventListener('mozfullscreenchange', this.onFullScreenChanged);
810
+ document.removeEventListener('MSFullscreenChange', this.onFullScreenChanged);
811
+ }
812
+
813
+ if (this.playlistController) {
814
+ this.playlistController.destroy();
815
+ }
816
+
817
+ const parent = this.$el.parentNode;
818
+ this.$el.removeChild(this.$inner);
819
+
820
+ if (parent) {
821
+ parent.removeChild(this.$el);
822
+ }
823
+ }
824
+
825
+ static addStyles(styles: $Shape<Player$Styles>) {
826
+ appendStyles(extend({}, DEFAULT_STYLES, styles));
827
+ }
828
+
829
+ static canPlayHLS = !(isIE() || isIE11()) || hasFlashPlayer
830
+ }
831
+
832
+ function _windowWidth() {
833
+ const de = document.documentElement;
834
+ return de ? de.clientWidth : null;
835
+ }
836
+
837
+ function _windowHeight() {
838
+ const de = document.documentElement;
839
+ return de ? de.clientHeight : null;
840
+ }
841
+
842
+ /* set correct width/height for fullsize mode */
843
+ function _setFullSize(el: HTMLElement) {
844
+ const w = _windowWidth();
845
+ const h = _windowHeight();
846
+ if (typeof w === 'number' && typeof h === 'number') {
847
+ _normalizeSize(el, w, h);
848
+ }
849
+ }
850
+
851
+ /* set correct width/height */
852
+ function _normalizeSize(el: HTMLElement, w: number, h: number) {
853
+ el.style.width = `${w}px`;
854
+ el.style.height = `${h}px`;
855
+ }
856
+
857
+ function _clearSize(el: HTMLElement) {
858
+ el.style.width = '';
859
+ el.style.height = '';
860
+ }
861
+
862
+ function _stop(e: Event) {
863
+ e.stopPropagation();
864
+ }