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/state.js ADDED
@@ -0,0 +1,474 @@
1
+ // @flow
2
+ import Entity from './entity';
3
+
4
+ import MicroEvent from './microevent';
5
+
6
+ import {
7
+ uidGenerator,
8
+ each,
9
+ extend,
10
+ findIndex,
11
+ find,
12
+ map,
13
+ filter
14
+ } from './utils';
15
+
16
+ import { getStoredData, storeData } from './extensions/helpers/storage';
17
+ import loadVTT from './extensions/helpers/vtt-loader';
18
+ import load from './extensions/helpers/transport';
19
+ import isMobile from './helpers/isMobile';
20
+
21
+ import {
22
+ APPROVED_TIMEDATA_STATUS,
23
+ TRANSLATABLE_TIMEDATA_STATUS,
24
+ UNTRANSLATED_TIMEDATA_STATUS
25
+ } from './config/statuses';
26
+
27
+ import {
28
+ DEFAULT_CC_BG_COLOR,
29
+ DEFAULT_CC_FONT_FAMILY,
30
+ DEFAULT_CC_FONT_SIZE,
31
+ DEFAULT_CC_LOCATION,
32
+ DEFAULT_CC_TEXT_COLOR
33
+ } from './config/cc';
34
+
35
+ import type { Player$Logger } from './types/Logger';
36
+ import type {
37
+ Player$State,
38
+ Player$StateCC,
39
+ Player$StateTOC
40
+ } from './types/State';
41
+ import type { Player$Source, Player$TimeDataSource } from './types/Source';
42
+ // , Player$CCLocation
43
+ // import type { Player$TimeData } from './types/TimeData'
44
+
45
+ const OFF_IDX = 0;
46
+
47
+ const OFF_ITEM: Player$TimeDataSource = {
48
+ label: 'None',
49
+ srclang: '',
50
+ src: '',
51
+ state: APPROVED_TIMEDATA_STATUS
52
+ };
53
+
54
+ const LOCALSTORAGE_CC_KEYS: { [key: $Keys<Player$StateCC>]: string } = {
55
+ color: 'fontcolor',
56
+ bgcolor: 'bgcolor',
57
+ fontSize: 'fontsize',
58
+ fontFamily: 'fontfamily',
59
+ location: 'cc_location',
60
+ lang: 'cclang'
61
+ };
62
+
63
+ const TOC_LANG_STORAGE_KEY = 'toclang';
64
+
65
+ type Reducer = (
66
+ bus: MicroEvent,
67
+ state: Player$State,
68
+ ...args: Array<any>
69
+ ) => Player$State;
70
+
71
+ type PreparedSource = {
72
+ sources: Player$TimeDataSource[],
73
+ current: ?Player$TimeDataSource,
74
+ };
75
+
76
+ const actions: { [key: string]: Reducer } = {
77
+ theaterchanging(buse, state) {
78
+ return extend({}, state, { isTheaterMode: !state.isTheaterMode });
79
+ },
80
+ fullscreenchanging(bus, state, isFullScreen: ?boolean) {
81
+ isFullScreen =
82
+ typeof isFullScreen === 'boolean' ? isFullScreen : !state.isFullScreen;
83
+ return extend({}, state, { isFullScreen });
84
+ },
85
+ cclang(bus, state, lang: string) {
86
+ const sources = state.cc.sources;
87
+ const idx = Math.max(
88
+ findIndex(sources, (d) => d.srclang === lang),
89
+ OFF_IDX
90
+ );
91
+ const source = sources[idx];
92
+
93
+ if (!source) {
94
+ return state;
95
+ }
96
+
97
+ if (source.state === APPROVED_TIMEDATA_STATUS) {
98
+ storeData(LOCALSTORAGE_CC_KEYS.lang, lang);
99
+ }
100
+
101
+ const cc = extend({}, state.cc, { lang, loading: false });
102
+ const res: Player$State = extend({}, state, { cc });
103
+
104
+ bus.emit('captionschange', source);
105
+ if (source.srclang) {
106
+ res.cc.loading = true;
107
+ _timedataLoader(bus, 'refreshcaptions', source);
108
+ // } else {
109
+ // cc.timedata = [];
110
+ }
111
+
112
+ if (!state.cc.lang || !lang) {
113
+ bus.emit('cclayoutchange', {
114
+ mode: (lang && state.cc.location) || 'over',
115
+ fontSize: state.cc.fontSize
116
+ });
117
+ }
118
+ return res;
119
+ },
120
+ ccsources(
121
+ bus,
122
+ state,
123
+ sources: Player$TimeDataSource[],
124
+ lazy: boolean = false
125
+ ) {
126
+ const preparedCC = _prepareSources(sources, state.cc.lang);
127
+ sources = preparedCC.sources;
128
+ const lang = (preparedCC.current && preparedCC.current.srclang) || '';
129
+ if (!lazy) {
130
+ setTimeout(() => bus.emit('cclang', lang), 5);
131
+ }
132
+ const cc = extend({}, state.cc, { sources, lang, timedata: [] });
133
+ return extend({}, state, { cc });
134
+ },
135
+ refreshcaptions(bus, state, timedata, lang) {
136
+ const cc = extend({}, state.cc, { timedata });
137
+ cc.timedataLang = lang;
138
+ cc.loading = false;
139
+ return extend({}, state, { cc });
140
+ },
141
+ cclocation(bus, state, location) {
142
+ storeData(LOCALSTORAGE_CC_KEYS.location, location);
143
+ bus.emit('cclayoutchange', {
144
+ mode: (state.cc.lang && location) || 'over',
145
+ fontSize: state.cc.fontSize
146
+ });
147
+ const cc = extend({}, state.cc, { location });
148
+ return extend({}, state, { cc });
149
+ },
150
+ ccfontfamily(bus, state, fontFamily) {
151
+ storeData(LOCALSTORAGE_CC_KEYS.fontFamily, fontFamily);
152
+ const cc = extend({}, state.cc, { fontFamily });
153
+ return extend({}, state, { cc });
154
+ },
155
+ ccfontsize(bus, state, fontSize) {
156
+ storeData(LOCALSTORAGE_CC_KEYS.fontSize, fontSize);
157
+ bus.emit('cclayoutchange', {
158
+ mode: (state.cc.lang && state.cc.location) || 'over',
159
+ fontSize: fontSize
160
+ });
161
+ const cc = extend({}, state.cc, { fontSize });
162
+ return extend({}, state, { cc });
163
+ },
164
+ ccbgcolor(bus, state, bgcolor) {
165
+ storeData(LOCALSTORAGE_CC_KEYS.bgcolor, bgcolor);
166
+ const cc = extend({}, state.cc, { bgcolor });
167
+ return extend({}, state, { cc });
168
+ },
169
+ cccolor(bus, state, color) {
170
+ storeData(LOCALSTORAGE_CC_KEYS.color, color);
171
+ const cc = extend({}, state.cc, { color });
172
+ return extend({}, state, { cc });
173
+ },
174
+ chaptersloaded(bus, state, timedata, lang) {
175
+ const toc = extend({}, state.toc, { timedata });
176
+ toc.timedataLang = lang;
177
+ return extend({}, state, { toc });
178
+ },
179
+ tocsources(bus, state, sources: Player$TimeDataSource[]) {
180
+ const toc = _toc();
181
+ const preparedTOC = _prepareSources(sources, toc.lang);
182
+ toc.sources = preparedTOC.sources;
183
+ toc.lang = (preparedTOC.current && preparedTOC.current.srclang) || '';
184
+ const tocsource = find(toc.sources, (s) => s.srclang === toc.lang);
185
+ if (tocsource && tocsource.srclang) {
186
+ _timedataLoader(bus, 'chaptersloaded', tocsource);
187
+ } else {
188
+ const idx = 1;
189
+ const defsource =
190
+ find(toc.sources, (s) => !!s.default) || toc.sources[idx];
191
+ _timedataLoader(bus, 'chaptersloaded', defsource);
192
+ }
193
+
194
+ return extend({}, state, { toc });
195
+ },
196
+ changesource(bus, state, source: Player$Source) {
197
+ const cc = _cc();
198
+ const preparedCC = _prepareSources(source.cc, cc.lang);
199
+ cc.sources = preparedCC.sources;
200
+ cc.lang = (preparedCC.current && preparedCC.current.srclang) || '';
201
+ const ccsource = find(cc.sources, (s) => s.srclang === cc.lang);
202
+ if (ccsource && ccsource.srclang) {
203
+ _timedataLoader(bus, 'refreshcaptions', ccsource);
204
+ } else {
205
+ const idx = 1;
206
+ const defsource = find(cc.sources, (s) => !!s.default) || cc.sources[idx];
207
+ _timedataLoader(bus, 'refreshcaptions', defsource);
208
+ }
209
+
210
+ const toc = _toc();
211
+ const preparedTOC = _prepareSources(source.chapters, toc.lang);
212
+ toc.sources = preparedTOC.sources;
213
+ toc.lang = (preparedTOC.current && preparedTOC.current.srclang) || '';
214
+ const tocsource = find(toc.sources, (s) => s.srclang === toc.lang);
215
+ if (tocsource && tocsource.srclang) {
216
+ _timedataLoader(bus, 'chaptersloaded', tocsource);
217
+ } else {
218
+ const idx = 1;
219
+ const defsource =
220
+ find(toc.sources, (s) => !!s.default) || toc.sources[idx];
221
+ _timedataLoader(bus, 'chaptersloaded', defsource);
222
+ }
223
+
224
+ return extend({}, state, { cc, toc });
225
+ },
226
+ toclang(bus, state, lang: string) {
227
+ const sources = state.toc.sources;
228
+ const idx = Math.max(
229
+ findIndex(sources, (d) => d.srclang === lang),
230
+ OFF_IDX
231
+ );
232
+ const source = sources[idx];
233
+
234
+ if (source.state === APPROVED_TIMEDATA_STATUS) {
235
+ storeData(TOC_LANG_STORAGE_KEY, lang);
236
+ }
237
+
238
+ const toc = extend({}, state.toc, { lang });
239
+ const res: Player$State = extend({}, state, { toc });
240
+
241
+ if (source.srclang) {
242
+ _timedataLoader(bus, 'chaptersloaded', source);
243
+ // } else {
244
+ // toc.timedata = [];
245
+ }
246
+ return res;
247
+ }
248
+ };
249
+
250
+ const DEFAULT_STATE: Player$State = {
251
+ isFullScreen: false,
252
+ isTheaterMode: false,
253
+
254
+ cc: {
255
+ color: DEFAULT_CC_TEXT_COLOR,
256
+ bgcolor: DEFAULT_CC_BG_COLOR,
257
+ fontSize: DEFAULT_CC_FONT_SIZE,
258
+ fontFamily: DEFAULT_CC_FONT_FAMILY,
259
+ location: DEFAULT_CC_LOCATION,
260
+ lang: null,
261
+ sources: [],
262
+ timedata: [],
263
+ timedataLang: '',
264
+ loading: false
265
+ },
266
+
267
+ toc: {
268
+ lang: null,
269
+ sources: [],
270
+ timedata: [],
271
+ timedataLang: ''
272
+ }
273
+ };
274
+
275
+ const cache: { [key: string]: Player$State } = {};
276
+
277
+ export default class StateEntity extends Entity {
278
+ _uid: string;
279
+
280
+ constructor(bus: MicroEvent, logger: Player$Logger) {
281
+ super(bus, logger);
282
+ this._uid = uidGenerator();
283
+ cache[this._uid] = extend({}, DEFAULT_STATE);
284
+ cache[this._uid].cc = _cc();
285
+
286
+ each(actions, (transformer, listener) => {
287
+ if (typeof listener === 'number') {
288
+ return;
289
+ }
290
+ bus.on(listener, (...args: Array<any>) => {
291
+ const old = cache[this._uid];
292
+ const state = transformer.apply(this, [bus, old].concat(args));
293
+ cache[this._uid] = state;
294
+ bus.emit('statechanged', state, old);
295
+ });
296
+ });
297
+ }
298
+
299
+ isFullScreen() {
300
+ return cache[this._uid].isFullScreen;
301
+ }
302
+
303
+ isTheaterMode() {
304
+ return cache[this._uid].isTheaterMode;
305
+ }
306
+
307
+ getCCLang() {
308
+ return cache[this._uid].cc.lang;
309
+ }
310
+
311
+ getCCTextColor() {
312
+ return cache[this._uid].cc.color;
313
+ }
314
+
315
+ getCCBgColor() {
316
+ return cache[this._uid].cc.bgcolor;
317
+ }
318
+
319
+ getCCFontSize() {
320
+ return cache[this._uid].cc.fontSize;
321
+ }
322
+
323
+ getCCFontFamily() {
324
+ return cache[this._uid].cc.fontFamily;
325
+ }
326
+
327
+ getCCLocation() {
328
+ return cache[this._uid].cc.location;
329
+ }
330
+
331
+ getCCSources() {
332
+ const cc = cache[this._uid].cc.sources || [];
333
+ if (isMobile()) {
334
+ return filter(
335
+ cc,
336
+ (source) => source.state !== UNTRANSLATED_TIMEDATA_STATUS
337
+ );
338
+ }
339
+
340
+ return cc;
341
+ }
342
+
343
+ getCCTimeData() {
344
+ return cache[this._uid].cc.timedata;
345
+ }
346
+
347
+ getCCTimeDataLang() {
348
+ return cache[this._uid].cc.timedataLang;
349
+ }
350
+
351
+ getSelectedCC() {
352
+ const state = cache[this._uid];
353
+ const { sources, lang } = state.cc;
354
+ const idx = Math.max(
355
+ findIndex(sources, (d) => d.srclang === lang),
356
+ OFF_IDX
357
+ );
358
+ return sources[idx];
359
+ }
360
+
361
+ isTranslatingCC() {
362
+ const state = cache[this._uid];
363
+ const { sources, lang, loading } = state.cc;
364
+ const idx = Math.max(
365
+ findIndex(sources, (d) => d.srclang === lang),
366
+ OFF_IDX
367
+ );
368
+ return loading && sources[idx].state === TRANSLATABLE_TIMEDATA_STATUS;
369
+ }
370
+
371
+ getTOCSources() {
372
+ return cache[this._uid].toc.sources;
373
+ }
374
+
375
+ getTOCLang() {
376
+ return cache[this._uid].toc.lang;
377
+ }
378
+
379
+ getTOCTimeData() {
380
+ return cache[this._uid].toc.timedata;
381
+ }
382
+
383
+ getTOCTimeDataLang() {
384
+ return cache[this._uid].toc.timedataLang;
385
+ }
386
+ }
387
+
388
+ function _cc(): Player$StateCC {
389
+ const res = extend({}, DEFAULT_STATE.cc);
390
+ each(LOCALSTORAGE_CC_KEYS, (key, prop) => {
391
+ res[prop] = getStoredData(key, DEFAULT_STATE.cc[prop]);
392
+ });
393
+ return res;
394
+ }
395
+
396
+ function _toc(): Player$StateTOC {
397
+ const res: Player$StateTOC = extend({}, DEFAULT_STATE.toc);
398
+ res.lang = getStoredData(TOC_LANG_STORAGE_KEY, DEFAULT_STATE.toc.lang);
399
+ return res;
400
+ }
401
+
402
+ function _sortSource(
403
+ sources: Player$TimeDataSource[]
404
+ ): Player$TimeDataSource[] {
405
+ return sources.sort((s1, s2) => {
406
+ const st1 =
407
+ typeof s1.state === 'number' ? s1.state : APPROVED_TIMEDATA_STATUS;
408
+ const st2 =
409
+ typeof s2.state === 'number' ? s1.state : APPROVED_TIMEDATA_STATUS;
410
+
411
+ if (st1 === st2) {
412
+ return s1.label < s2.label ? -1 : 1;
413
+ }
414
+ if (typeof st1 === 'number' && typeof st2 === 'number') {
415
+ return st2 - st1;
416
+ }
417
+ return 0;
418
+ });
419
+ }
420
+
421
+ function _normalizeSource(
422
+ source: Player$TimeDataSource
423
+ ): Player$TimeDataSource {
424
+ const state =
425
+ typeof source.state === 'number' ? source.state : APPROVED_TIMEDATA_STATUS;
426
+ return extend({}, source, { state });
427
+ }
428
+
429
+ function _prepareSources(
430
+ input: ?(Player$TimeDataSource[]),
431
+ lang: ?string
432
+ ): PreparedSource {
433
+ const normalized = _sortSource(map(input || [], _normalizeSource));
434
+ const sources = normalized.length ? [OFF_ITEM].concat(normalized) : [];
435
+
436
+ let current = find(
437
+ sources,
438
+ (s) => s.srclang === lang && s.state !== TRANSLATABLE_TIMEDATA_STATUS
439
+ );
440
+ if (!current) {
441
+ let filtered = filter(
442
+ sources,
443
+ (s) => s.state !== TRANSLATABLE_TIMEDATA_STATUS
444
+ );
445
+ // 1 - because OFF is the first
446
+ const idx = 1;
447
+ current = find(sources, (s) => !!s.default) || filtered[idx];
448
+ }
449
+
450
+ return { sources, current };
451
+ }
452
+
453
+ function _timedataLoader(
454
+ bus: MicroEvent,
455
+ event: "chaptersloaded" | "refreshcaptions",
456
+ source: ?Player$TimeDataSource
457
+ ) {
458
+ if (!source || !source.src) {
459
+ bus.emit(event, []);
460
+ return;
461
+ }
462
+
463
+ const srclang = source.srclang;
464
+ const error = () => bus.emit(event, [], srclang);
465
+ if (source.type === 'json') {
466
+ load({
467
+ url: source.src,
468
+ success: (resp) => bus.emit(event, JSON.parse(resp.data), srclang),
469
+ error
470
+ });
471
+ } else {
472
+ loadVTT(source.src, (m) => bus.emit(event, m, srclang), error);
473
+ }
474
+ }