@js-toolkit/web-utils 1.66.0 → 1.68.0

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 (120) hide show
  1. package/EventEmitterListener.d.ts +3 -3
  2. package/EventEmitterListener.js +222 -1
  3. package/EventEmitterListener.utils.d.ts +24 -13
  4. package/EventEmitterListener.utils.js +41 -1
  5. package/EventListeners.js +58 -1
  6. package/FullscreenController.js +193 -1
  7. package/README.md +159 -20
  8. package/WakeLockController.js +76 -1
  9. package/base64ToDataUrl.js +3 -1
  10. package/blobToDataUrl.js +10 -1
  11. package/checkPermission.js +8 -1
  12. package/copyToClipboard.js +37 -1
  13. package/createLoop.js +30 -1
  14. package/createRafLoop.js +56 -1
  15. package/dataUrlToBlob.js +13 -1
  16. package/fromBase64.js +10 -1
  17. package/fullscreen.js +167 -1
  18. package/fullscreenUtils.js +37 -1
  19. package/getAspectRatio.js +8 -1
  20. package/getBrowserLanguage.js +10 -1
  21. package/getCurrentScriptUrl.js +4 -1
  22. package/getEventAwaiter.js +41 -1
  23. package/getGeoCoordinates.js +6 -1
  24. package/getGeoLocality.js +19 -1
  25. package/getInnerRect.js +8 -1
  26. package/getInnerXDimensions.js +9 -1
  27. package/getInnerYDimensions.js +9 -1
  28. package/getPinchZoomHandlers.js +134 -1
  29. package/getRandomID.js +4 -1
  30. package/getScreenSize.js +23 -1
  31. package/getSecondsCounter.js +47 -1
  32. package/iframe/getAutoConnector.js +251 -1
  33. package/iframe/getOriginFromMessage.js +3 -1
  34. package/iframe/isIframeLoaded.js +9 -1
  35. package/iframe/messages.d.ts +2 -2
  36. package/iframe/messages.js +50 -1
  37. package/iframe/utils.js +33 -1
  38. package/imageToBlob.js +20 -1
  39. package/isImageTypeSupported.js +8 -1
  40. package/isWebPSupported.js +15 -1
  41. package/loadImage.js +29 -1
  42. package/loadScript.d.ts +1 -1
  43. package/loadScript.js +67 -1
  44. package/media/Capabilities.js +44 -1
  45. package/media/MediaNotAttachedError.d.ts +1 -1
  46. package/media/MediaNotAttachedError.js +6 -1
  47. package/media/MediaStreamController.js +84 -1
  48. package/media/PipController.d.ts +2 -2
  49. package/media/PipController.js +140 -1
  50. package/media/TextTracksController/TextTracksController.d.ts +0 -3
  51. package/media/TextTracksController/TextTracksController.js +251 -1
  52. package/media/TextTracksController/index.js +1 -1
  53. package/media/TextTracksController/utils.js +147 -1
  54. package/media/getDurationTime.js +3 -1
  55. package/media/getMediaSource.js +11 -1
  56. package/media/getSourceBuffer.js +5 -1
  57. package/media/isMediaSeekable.js +4 -1
  58. package/media/parseCueText.js +224 -1
  59. package/media/resetMedia.js +17 -1
  60. package/media/timeRanges.js +9 -1
  61. package/media/toggleNativeSubtitles.js +21 -1
  62. package/metrics/ga/DataLayerProxy.js +11 -1
  63. package/metrics/ga/getHandler.js +99 -1
  64. package/metrics/ga/types.js +1 -1
  65. package/metrics/types.js +1 -1
  66. package/metrics/yandex/DataLayerProxy.js +11 -1
  67. package/metrics/yandex/getHandler.js +63 -1
  68. package/metrics/yandex/types.js +2 -1
  69. package/onDOMReady.js +12 -1
  70. package/onPageReady.js +27 -1
  71. package/package.json +19 -16
  72. package/patchConsoleLogging.js +27 -1
  73. package/performance/getNavigationTiming.js +14 -1
  74. package/platform/Semver.js +23 -1
  75. package/platform/getChromeVersion.d.ts +2 -0
  76. package/platform/getChromeVersion.js +16 -0
  77. package/platform/getIOSVersion.js +18 -1
  78. package/platform/getPlatformInfo.js +49 -1
  79. package/platform/isAirPlayAvailable.js +3 -1
  80. package/platform/isAndroid.js +7 -1
  81. package/platform/isChrome.js +7 -1
  82. package/platform/isEMESupported.js +9 -1
  83. package/platform/isIOS.js +9 -1
  84. package/platform/isMSESupported.js +16 -1
  85. package/platform/isMacOS.js +12 -1
  86. package/platform/isMediaCapabilitiesSupported.js +6 -1
  87. package/platform/isMobile.js +16 -1
  88. package/platform/isMobileSimulation.js +7 -1
  89. package/platform/isSafari.js +14 -1
  90. package/platform/isScreenHDR.js +4 -1
  91. package/platform/isStandaloneApp.js +4 -1
  92. package/platform/isTelegramWebView.js +3 -1
  93. package/platform/isTouchSupported.js +4 -1
  94. package/preventDefault.d.ts +2 -2
  95. package/preventDefault.js +5 -1
  96. package/rafCallback.js +9 -1
  97. package/responsive/MediaQuery.d.ts +18 -0
  98. package/responsive/MediaQuery.js +40 -0
  99. package/responsive/MediaQueryListener.d.ts +19 -0
  100. package/responsive/MediaQueryListener.js +55 -0
  101. package/responsive/ViewSize.d.ts +45 -0
  102. package/responsive/ViewSize.js +82 -0
  103. package/responsive/getViewSizeQueryMap.d.ts +2 -0
  104. package/responsive/getViewSizeQueryMap.js +7 -0
  105. package/saveFileAs.js +22 -1
  106. package/serviceWorker/ServiceWorkerInstaller.d.ts +0 -1
  107. package/serviceWorker/ServiceWorkerInstaller.js +112 -1
  108. package/serviceWorker/utils.d.ts +1 -1
  109. package/serviceWorker/utils.js +86 -1
  110. package/stopPropagation.d.ts +2 -2
  111. package/stopPropagation.js +3 -1
  112. package/takeScreenshot.js +51 -1
  113. package/toBase64.js +9 -1
  114. package/toLocalPoint.js +9 -1
  115. package/types/index.js +2 -1
  116. package/types/refs.js +1 -1
  117. package/viewableTracker.js +69 -1
  118. package/webrtc/PeerConnection.js +212 -1
  119. package/webrtc/sdputils.js +417 -1
  120. package/ws/WSController.js +148 -1
@@ -1 +1,251 @@
1
- import{EventEmitter}from"@js-toolkit/utils/EventEmitter";import{EventListeners}from"../../EventListeners";import{MediaNotAttachedError}from"../MediaNotAttachedError";import{parseTextTracks,setActiveTextTrack,addTextTracks,isIOSFullscreen,splitRows,buildCueId}from"./utils";function dispatchNativeEvent(t,e,s){t.dispatchEvent(new CustomEvent(e,{detail:s}))}export class TextTracksController extends EventEmitter{options;eventListeners=new EventListeners;addedTracks=[];textTrackList=[];media;textTrack;nextTextTrack;get Events(){return TextTracksController.Events}constructor(t){super(),this.options={emitNativeEvents:!1,hideActiveTrack:!0,preferCueRowLength:0},t&&this.setOptions(t)}setOptions(t){Object.assign(this.options,{...t,emitNativeEvents:t.emitNativeEvents??this.options.emitNativeEvents,hideActiveTrack:t.hideActiveTrack??this.options.hideActiveTrack,preferCueRowLength:t.preferCueRowLength??this.options.preferCueRowLength})}isAttached(){return!!this.media}getMediaElement(){if(!this.media)throw new MediaNotAttachedError;return this.media}detach(){this.eventListeners.removeAllListeners(),this.media=void 0,this.addedTracks=[],this.textTrackList=[],this.textTrack=void 0,this.nextTextTrack=void 0}attach(t){this.detach();const e=(()=>{const e=[];return s=>{const{activeCues:i}=s.target;if(!i)return;const{length:a}=i,{length:r}=e;let n=r!==a;const c=new Array(a);for(let t=0;t<a;t+=1){const s=i[t];s.id=s.id||buildCueId(s,t),s.rows=splitRows(s.text,this.options.preferCueRowLength),c[t]=s,n||e[t]?.id===s.id||(n=!0),e[t]=s}r>a&&e.splice(a-r),n&&(this.emit(this.Events.TextTrackCueChanged,{textTrack:s.target,cues:c}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackcuechange",{textTrack:s.target,cues:c}))}})(),s=()=>{this.textTrackList=parseTextTracks(t),this.emit(this.Events.TextTrackListChanged,{textTracks:this.textTrackList}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttracklistchange",{textTracks:this.textTrackList}),setActiveTextTrack(t,this.textTrack??this.nextTextTrack,this.options.hideActiveTrack&&!isIOSFullscreen(t))};this.media=t;let i=!1;const a=t=>{i||s(),this.eventListeners.scope(t).on("cuechange",e)},r=t=>{s(),this.eventListeners.scope(t).off("cuechange",e)};if(this.eventListeners.scope(this.media.textTracks).on("change",()=>{const{textTracks:e}=t,{nextTextTrack:s}=this;let i=-1;const{length:a}=e;for(let r=0;r<a;r+=1){const a=e[r];if(a.language===s?.language&&a.kind===s?.kind||isIOSFullscreen(t)||(a.mode="disabled"),"disabled"!==a.mode&&i>=0&&(a.mode="disabled"),"disabled"!==a.mode){if(i=r,!a.native&&!isIOSFullscreen(t)){const t=this.options.hideActiveTrack?"hidden":"showing";a.mode!==t&&(a.mode=t)}a.native&&a.language===s?.language&&a.kind===s.kind&&(a.mode="showing")}}const r=e[i]&&((this.textTrackList[i]&&{...this.textTrackList[i],mode:e[i].mode})??{id:e[i].id,kind:e[i].kind,language:e[i].language,label:e[i].label,mode:e[i].mode});this.textTrack?.language===r?.language&&this.textTrack?.kind===r?.kind&&this.textTrack?.mode===r?.mode||(this.textTrack=r,this.nextTextTrack=this.textTrack,this.emit(this.Events.CurrentTextTrackChanged,{textTrack:this.textTrack,index:i}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackchange",{textTrack:this.textTrack,index:i}))}).on("addtrack",({track:t})=>t&&a(t)).on("removetrack",({track:t})=>t&&r(t)),this.media.textTracks.length>0){this.textTrackList=parseTextTracks(t),i=!0;try{Array.prototype.forEach.call(this.media.textTracks,a),s()}finally{i=!1}}}getTextTracks(){return this.textTrackList}setTextTracks(t){const e=this.getMediaElement();if(this.eventListeners.scope(e,"@@setTextTracks").removeAllListeners(),this.addedTracks.forEach(t=>t.remove()),0===t.length)return;const s=()=>{addTextTracks(e,t,t=>this.addedTracks.push(t)),this.textTrackList=parseTextTracks(e)};e.readyState>=e.HAVE_CURRENT_DATA?s():this.eventListeners.scope(e,"@@setTextTracks").once("loadeddata",s)}getActiveTextTrack(){return this.textTrack}setActiveTextTrack(t){const e=this.getMediaElement();return this.nextTextTrack=t&&this.textTrackList.find(e=>e.language===t.language&&(!t.kind||e.kind===t.kind)),setActiveTextTrack(e,this.nextTextTrack,this.options.hideActiveTrack&&!isIOSFullscreen(e))}destroy(){this.detach(),this.removeAllListeners()}[Symbol.dispose](){this.destroy()}}!function(t){let e;!function(t){t.TextTrackListChanged="TrackListChanged",t.CurrentTextTrackChanged="CurrentTextTrackChanged",t.TextTrackCueChanged="TextTrackCueChanged"}(e=t.Events||(t.Events={}))}(TextTracksController||(TextTracksController={}));
1
+ import { EventEmitter } from '@js-toolkit/utils/EventEmitter';
2
+ import { EventListeners } from '../../EventListeners';
3
+ import { MediaNotAttachedError } from '../MediaNotAttachedError';
4
+ import { parseTextTracks, setActiveTextTrack, addTextTracks, isIOSFullscreen, splitRows, buildCueId, } from './utils';
5
+ function dispatchNativeEvent(media, type, data) {
6
+ media.dispatchEvent(new CustomEvent(type, { detail: data }));
7
+ }
8
+ export class TextTracksController extends EventEmitter {
9
+ options;
10
+ eventListeners = new EventListeners();
11
+ addedTracks = [];
12
+ textTrackList = [];
13
+ media;
14
+ /** Already set. */
15
+ textTrack;
16
+ /** To be set. */
17
+ nextTextTrack;
18
+ // eslint-disable-next-line class-methods-use-this
19
+ get Events() {
20
+ return TextTracksController.Events;
21
+ }
22
+ constructor(options) {
23
+ super();
24
+ this.options = {
25
+ emitNativeEvents: false,
26
+ hideActiveTrack: true,
27
+ preferCueRowLength: 0,
28
+ };
29
+ if (options)
30
+ this.setOptions(options);
31
+ }
32
+ setOptions(options) {
33
+ Object.assign(this.options, {
34
+ ...options,
35
+ emitNativeEvents: options.emitNativeEvents ?? this.options.emitNativeEvents,
36
+ hideActiveTrack: options.hideActiveTrack ?? this.options.hideActiveTrack,
37
+ preferCueRowLength: options.preferCueRowLength ?? this.options.preferCueRowLength,
38
+ });
39
+ }
40
+ isAttached() {
41
+ return !!this.media;
42
+ }
43
+ getMediaElement() {
44
+ if (!this.media)
45
+ throw new MediaNotAttachedError();
46
+ return this.media;
47
+ }
48
+ detach() {
49
+ this.eventListeners.removeAllListeners();
50
+ this.media = undefined;
51
+ this.addedTracks = [];
52
+ this.textTrackList = [];
53
+ this.textTrack = undefined;
54
+ this.nextTextTrack = undefined;
55
+ }
56
+ attach(media) {
57
+ // if (this.media === media) return;
58
+ this.detach();
59
+ const changeHandler = () => {
60
+ // const textTracks = media.textTracks as PartialSome<TextTrackList, number>;
61
+ const { textTracks } = media;
62
+ const { nextTextTrack } = this;
63
+ let newCurrentIndex = -1;
64
+ // console.log(
65
+ // 'onchange',
66
+ // nextTextTrack,
67
+ // Array.from(textTracks).map((tt) =>
68
+ // JSON.stringify({ lang: tt.language, mode: tt.mode, native: tt.native })
69
+ // ),
70
+ // media.webkitDisplayingFullscreen
71
+ // );
72
+ const { length } = textTracks;
73
+ for (let i = 0; i < length; i += 1) {
74
+ const track = textTracks[i];
75
+ // Disable default texttracks but allow select tracks in iOS native menu in fullscreen
76
+ if ((track.language !== nextTextTrack?.language || track.kind !== nextTextTrack?.kind) &&
77
+ !isIOSFullscreen(media)) {
78
+ track.mode = 'disabled';
79
+ }
80
+ // Disable other tracks if some track already active
81
+ if (track.mode !== 'disabled' && newCurrentIndex >= 0) {
82
+ track.mode = 'disabled';
83
+ }
84
+ if (track.mode !== 'disabled') {
85
+ // console.log(nextTextTrack?.lang, track.mode);
86
+ newCurrentIndex = i;
87
+ // In iOS we use toggleNativeSubtitles so mode will be 'showing' in fullscreen and track.native will be 'true'.
88
+ // Also keep 'showing' mode if iOS and video fullscreen.
89
+ if (!track.native && !isIOSFullscreen(media)) {
90
+ // If texttracks from manifest (eg. m3u8) the mode changes to 'showing'
91
+ // so we need to set 'hidden' or leave it as is.
92
+ const mode = this.options.hideActiveTrack ? 'hidden' : 'showing';
93
+ if (track.mode !== mode)
94
+ track.mode = mode;
95
+ }
96
+ if (track.native &&
97
+ track.language === nextTextTrack?.language &&
98
+ track.kind === nextTextTrack.kind) {
99
+ track.mode = 'showing';
100
+ }
101
+ }
102
+ }
103
+ const newCurrentTrack =
104
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
105
+ textTracks[newCurrentIndex] &&
106
+ ((this.textTrackList.at(newCurrentIndex) && {
107
+ ...this.textTrackList[newCurrentIndex],
108
+ mode: textTracks[newCurrentIndex].mode,
109
+ }) ??
110
+ {
111
+ id: textTracks[newCurrentIndex].id,
112
+ kind: textTracks[newCurrentIndex].kind,
113
+ language: textTracks[newCurrentIndex].language,
114
+ label: textTracks[newCurrentIndex].label,
115
+ mode: textTracks[newCurrentIndex].mode,
116
+ });
117
+ // console.log('onchange end', nextTextTrack, newCurrentIndex, newCurrentTrack);
118
+ if (this.textTrack?.language !== newCurrentTrack?.language ||
119
+ this.textTrack?.kind !== newCurrentTrack?.kind ||
120
+ this.textTrack?.mode !== newCurrentTrack?.mode) {
121
+ this.textTrack = newCurrentTrack;
122
+ this.nextTextTrack = this.textTrack;
123
+ this.emit(this.Events.CurrentTextTrackChanged, {
124
+ textTrack: this.textTrack,
125
+ index: newCurrentIndex,
126
+ });
127
+ if (this.options.emitNativeEvents) {
128
+ dispatchNativeEvent(media, 'texttrackchange', {
129
+ textTrack: this.textTrack,
130
+ index: newCurrentIndex,
131
+ });
132
+ }
133
+ }
134
+ };
135
+ const cueChangeHandler = (() => {
136
+ const lastCues = [];
137
+ return (event) => {
138
+ const { activeCues } = event.target;
139
+ if (!activeCues)
140
+ return;
141
+ const { length: activeCuesLength } = activeCues;
142
+ const { length: lastCuesLength } = lastCues;
143
+ // Because cuechange triggered twice.
144
+ let changed = lastCuesLength !== activeCuesLength;
145
+ const cues = new Array(activeCuesLength);
146
+ for (let i = 0; i < activeCuesLength; i += 1) {
147
+ const cue = activeCues[i];
148
+ cue.id = cue.id || buildCueId(cue, i);
149
+ cue.rows = splitRows(cue.text, this.options.preferCueRowLength);
150
+ cues[i] = cue;
151
+ if (!changed && lastCues[i]?.id !== cue.id) {
152
+ changed = true;
153
+ }
154
+ lastCues[i] = cue;
155
+ }
156
+ // Trim
157
+ if (lastCuesLength > activeCuesLength) {
158
+ lastCues.splice(activeCuesLength - lastCuesLength);
159
+ }
160
+ if (changed) {
161
+ this.emit(this.Events.TextTrackCueChanged, { textTrack: event.target, cues });
162
+ if (this.options.emitNativeEvents) {
163
+ dispatchNativeEvent(media, 'texttrackcuechange', { textTrack: event.target, cues });
164
+ }
165
+ }
166
+ };
167
+ })();
168
+ const onTextTracksUpdate = () => {
169
+ this.textTrackList = parseTextTracks(media);
170
+ this.emit(this.Events.TextTrackListChanged, { textTracks: this.textTrackList });
171
+ if (this.options.emitNativeEvents) {
172
+ dispatchNativeEvent(media, 'texttracklistchange', { textTracks: this.textTrackList });
173
+ }
174
+ setActiveTextTrack(media, this.textTrack ?? this.nextTextTrack, this.options.hideActiveTrack && !isIOSFullscreen(media));
175
+ };
176
+ this.media = media;
177
+ let lockUpdate = false;
178
+ const addTrack = (track) => {
179
+ if (!lockUpdate)
180
+ onTextTracksUpdate();
181
+ this.eventListeners.scope(track).on('cuechange', cueChangeHandler);
182
+ };
183
+ const removeTrack = (track) => {
184
+ onTextTracksUpdate();
185
+ this.eventListeners.scope(track).off('cuechange', cueChangeHandler);
186
+ };
187
+ this.eventListeners
188
+ .scope(this.media.textTracks)
189
+ .on('change', changeHandler)
190
+ .on('addtrack', ({ track }) => track && addTrack(track))
191
+ .on('removetrack', ({ track }) => track && removeTrack(track));
192
+ if (this.media.textTracks.length > 0) {
193
+ this.textTrackList = parseTextTracks(media);
194
+ lockUpdate = true;
195
+ try {
196
+ Array.prototype.forEach.call(this.media.textTracks, addTrack);
197
+ onTextTracksUpdate();
198
+ }
199
+ finally {
200
+ lockUpdate = false;
201
+ }
202
+ }
203
+ }
204
+ getTextTracks() {
205
+ return this.textTrackList;
206
+ }
207
+ setTextTracks(textTrackList) {
208
+ const media = this.getMediaElement();
209
+ this.eventListeners.scope(media, '@@setTextTracks').removeAllListeners();
210
+ this.addedTracks.forEach((el) => el.remove());
211
+ if (textTrackList.length === 0)
212
+ return;
213
+ const addTracks = () => {
214
+ addTextTracks(media, textTrackList, (el) => this.addedTracks.push(el));
215
+ // Because event 'addtrack' will be fired in the next tick.
216
+ this.textTrackList = parseTextTracks(media);
217
+ };
218
+ if (media.readyState >= media.HAVE_CURRENT_DATA) {
219
+ addTracks();
220
+ }
221
+ else {
222
+ this.eventListeners.scope(media, '@@setTextTracks').once('loadeddata', addTracks);
223
+ }
224
+ }
225
+ getActiveTextTrack() {
226
+ return this.textTrack;
227
+ }
228
+ setActiveTextTrack(tt) {
229
+ const media = this.getMediaElement();
230
+ this.nextTextTrack =
231
+ tt &&
232
+ this.textTrackList.find((t) => t.language === tt.language && (!tt.kind || t.kind === tt.kind));
233
+ return setActiveTextTrack(media, this.nextTextTrack, this.options.hideActiveTrack && !isIOSFullscreen(media));
234
+ }
235
+ destroy() {
236
+ this.detach();
237
+ this.removeAllListeners();
238
+ }
239
+ [Symbol.dispose]() {
240
+ this.destroy();
241
+ }
242
+ }
243
+ // eslint-disable-next-line @typescript-eslint/no-namespace
244
+ (function (TextTracksController) {
245
+ let Events;
246
+ (function (Events) {
247
+ Events["TextTrackListChanged"] = "TrackListChanged";
248
+ Events["CurrentTextTrackChanged"] = "CurrentTextTrackChanged";
249
+ Events["TextTrackCueChanged"] = "TextTrackCueChanged";
250
+ })(Events = TextTracksController.Events || (TextTracksController.Events = {}));
251
+ })(TextTracksController || (TextTracksController = {}));
@@ -1 +1 @@
1
- export*from"./TextTracksController";
1
+ export * from './TextTracksController';
@@ -1 +1,147 @@
1
- import{isIOS}from"../../platform/isIOS";const DETACHED_GROUP_ID="__detached__";export function fakeDetachTextTracks(t){Array.prototype.forEach.call(t.textTracks,t=>{const e=t;e.customGroupId&&(e.customGroupId="__detached__")})}export function parseTextTracks(t){return 0===t.textTracks.length?[]:Array.prototype.reduce.call(t.textTracks,(t,{customGroupId:e,id:n,kind:r,language:l,label:a})=>("__detached__"!==e&&l&&t.push({id:n,kind:r,language:l,label:a??""}),t),[])}export function isIOSFullscreen(t){return isIOS()&&!!t.webkitDisplayingFullscreen}export function findTextTrack(t,e){return Array.prototype.find.call(t.textTracks,({mode:t,language:n})=>e.some(e=>!(null!=e.mode&&e.mode!==t||null!=e.language&&e.language!==n)))}export function setActiveTextTrack(t,e,n){const{textTracks:r}=t,{length:l}=r;if(0===l)return!1;let a=!1,o=!1;for(let t=0;t<l;t+=1){const l=r[t];if(o||l.language!==e?.language||e.kind&&l.kind!==e.kind)"disabled"!==l.mode&&(l.mode="disabled",a=!0);else{const t=n?"hidden":"showing";l.mode=t,o=!0,a=!0}}return a}export function addTextTracks(t,e,n){const r=new Set;for(const{language:e,kind:n}of t.textTracks)r.add(`${e} ${n}`);e.forEach(e=>{const l=e.kind??"subtitles";if(!r.has(`${e.language} ${l}`)){const r=document.createElement("track");r.src=e.src,r.srclang=e.language,r.label=e.label,r.kind=l,r.default=!1,n(t.appendChild(r))}})}export function buildCueId(t,e){return`${t.startTime}-${e}`}export function splitRows(t,e){if(e<=0)return t.split(/\r?\n/);const n=[];let r=0,l=r,a="";const{length:o}=t;for(let c=0;c<=o;c+=1){const o=t[c];a.length>0&&r<l&&(n[l]=null==o?a.trim():a.trimStart(),a=""),r=l;let i=n[r]??"";if("\n"===o||"\r\n"===o)a.length>0&&i.length+a.length<=e&&(i+=i.length>0?a:a.trimStart(),a=""),l+=1;else if(" "===o){if(a.length>0){i.length+a.length>e&&i.length>0?(l+=1,i=i.trimEnd()):(i+=0===i.length?a.trimStart():a,a="")}a+=o}else if(null==o&&a.length>0){i.length+a.length>e&&0!==i.length?(r+=1,i=a.trim()):i+=a}else o&&(a+=o);n[r]=i}return n}
1
+ import { isIOS } from '../../platform/isIOS';
2
+ const DETACHED_GROUP_ID = '__detached__';
3
+ /** Hack: MSE can't remove texttracks on detaching because of no browser api for that. */
4
+ export function fakeDetachTextTracks(media) {
5
+ Array.prototype.forEach.call(media.textTracks, (textTrack) => {
6
+ const track = textTrack;
7
+ if (track.customGroupId) {
8
+ track.customGroupId = DETACHED_GROUP_ID;
9
+ }
10
+ });
11
+ }
12
+ export function parseTextTracks(media) {
13
+ if (media.textTracks.length === 0)
14
+ return [];
15
+ return (Array.prototype.reduce).call(media.textTracks, (acc, { customGroupId, id, kind, language, label }) => {
16
+ if (customGroupId !== DETACHED_GROUP_ID && language) {
17
+ acc.push({ id, kind, language, label: label ?? '' });
18
+ }
19
+ return acc;
20
+ }, []);
21
+ }
22
+ export function isIOSFullscreen(media) {
23
+ return isIOS() && !!media.webkitDisplayingFullscreen;
24
+ }
25
+ export function findTextTrack(media, conditions) {
26
+ return Array.prototype.find.call(media.textTracks, ({ mode, language }) => {
27
+ return conditions.some((condition) => {
28
+ return ((condition.mode == null || condition.mode === mode) &&
29
+ (condition.language == null || condition.language === language));
30
+ });
31
+ });
32
+ }
33
+ export function setActiveTextTrack(media, tt, hideActiveTrack) {
34
+ const { textTracks } = media;
35
+ const { length } = textTracks;
36
+ if (length === 0)
37
+ return false;
38
+ // console.log('setActiveTextTrack', tt);
39
+ let changed = false;
40
+ let activated = false;
41
+ for (let i = 0; i < length; i += 1) {
42
+ const track = textTracks[i];
43
+ // Hide active track in favor of custom/native display cues and disable others.
44
+ if (!activated && track.language === tt?.language && (!tt.kind || track.kind === tt.kind)) {
45
+ // Show native subtitles for IOS in video fullscreen mode
46
+ // Otherwise hide subtitles in favor of custom implementation
47
+ const nextMode = hideActiveTrack ? 'hidden' : 'showing';
48
+ track.mode = nextMode;
49
+ activated = true;
50
+ changed = true;
51
+ }
52
+ else if (track.mode !== 'disabled') {
53
+ track.mode = 'disabled';
54
+ changed = true;
55
+ }
56
+ }
57
+ return changed;
58
+ }
59
+ /** Dynamically add text tracks if they not exist. */
60
+ export function addTextTracks(media, textTrackList, onAdd) {
61
+ // console.log('addTracks', media.textTracks.length, media.readyState);
62
+ const keySet = new Set();
63
+ for (const { language, kind } of media.textTracks) {
64
+ keySet.add(`${language} ${kind}`);
65
+ }
66
+ textTrackList.forEach((tt) => {
67
+ const kind = tt.kind ?? 'subtitles';
68
+ if (!keySet.has(`${tt.language} ${kind}`)) {
69
+ const trackEl = document.createElement('track');
70
+ trackEl.src = tt.src;
71
+ trackEl.srclang = tt.language;
72
+ trackEl.label = tt.label;
73
+ trackEl.kind = kind;
74
+ // Ignore `default` because the most times there are problems with loading vtt file
75
+ // because of track mode changed from `showing` to `disabled` in the middle of loading
76
+ // and therefore no cues are loaded.
77
+ trackEl.default = false;
78
+ // Add texttrack
79
+ onAdd(media.appendChild(trackEl));
80
+ }
81
+ });
82
+ }
83
+ export function buildCueId(cue, index) {
84
+ return `${cue.startTime}-${index}`;
85
+ }
86
+ export function splitRows(text, preferLineLength) {
87
+ if (preferLineLength <= 0)
88
+ return text.split(/\r?\n/);
89
+ const lines = [];
90
+ let lineIdx = 0;
91
+ let nextLineIdx = lineIdx;
92
+ let word = '';
93
+ const { length } = text;
94
+ for (let i = 0; i <= length; i += 1) {
95
+ const char = text[i];
96
+ // Oversized from the prev line
97
+ if (word.length > 0 && lineIdx < nextLineIdx) {
98
+ lines[nextLineIdx] = char == null ? word.trim() : word.trimStart();
99
+ word = '';
100
+ }
101
+ lineIdx = nextLineIdx;
102
+ let line = lines[lineIdx] ?? '';
103
+ // Line break
104
+ if (char === '\n' || char === '\r\n') {
105
+ // Add last word to the current line or keep it for the next one.
106
+ if (word.length > 0 && line.length + word.length <= preferLineLength) {
107
+ line += line.length > 0 ? word : word.trimStart();
108
+ word = '';
109
+ }
110
+ nextLineIdx += 1;
111
+ }
112
+ // Word break
113
+ else if (char === ' ') {
114
+ if (word.length > 0) {
115
+ const oversize = line.length + word.length > preferLineLength;
116
+ // console.log(oversize, line, word, word.length);
117
+ if (oversize && line.length > 0) {
118
+ nextLineIdx += 1;
119
+ line = line.trimEnd();
120
+ }
121
+ else {
122
+ line += line.length === 0 ? word.trimStart() : word;
123
+ word = '';
124
+ }
125
+ }
126
+ word += char;
127
+ }
128
+ // The last word
129
+ else if (char == null && word.length > 0) {
130
+ const oversize = line.length + word.length > preferLineLength;
131
+ // console.log(char, oversize, line);
132
+ if (!oversize || line.length === 0) {
133
+ line += word;
134
+ }
135
+ else {
136
+ lineIdx += 1;
137
+ line = word.trim();
138
+ }
139
+ }
140
+ // Just add to word
141
+ else if (char) {
142
+ word += char;
143
+ }
144
+ lines[lineIdx] = line;
145
+ }
146
+ return lines;
147
+ }
@@ -1 +1,3 @@
1
- export function getDurationTime(i){return Number.isFinite(i.duration)&&i.duration>=0?i.duration:NaN}
1
+ export function getDurationTime(media) {
2
+ return Number.isFinite(media.duration) && media.duration >= 0 ? media.duration : NaN;
3
+ }
@@ -1 +1,11 @@
1
- export function getMediaSource(e){return"maybe"===e?window.ManagedMediaSource:"prefer"===e&&window.ManagedMediaSource||window.MediaSource}
1
+ export function getMediaSource(
2
+ /**
3
+ * `prefer` - returns ManagedMediaSource or MediaSource.
4
+ * `maybe` - returns ManagedMediaSource.
5
+ * Otherwise returns MediaSource.
6
+ */
7
+ managedMediaSource) {
8
+ if (managedMediaSource === 'maybe')
9
+ return window.ManagedMediaSource;
10
+ return (managedMediaSource === 'prefer' && window.ManagedMediaSource) || window.MediaSource; // || window.WebKitMediaSource;
11
+ }
@@ -1 +1,5 @@
1
- export function getSourceBuffer(e){return"maybe"===e?window.ManagedSourceBuffer:"prefer"===e&&window.ManagedSourceBuffer||window.SourceBuffer}
1
+ export function getSourceBuffer(managedMediaSource) {
2
+ if (managedMediaSource === 'maybe')
3
+ return window.ManagedSourceBuffer;
4
+ return (managedMediaSource === 'prefer' && window.ManagedSourceBuffer) || window.SourceBuffer; // || window.WebKitSourceBuffer;
5
+ }
@@ -1 +1,4 @@
1
- import{getTimeRangeDuration}from"./timeRanges";export function isMediaSeekable(e){return getTimeRangeDuration(e.seekable)>0}
1
+ import { getTimeRangeDuration } from './timeRanges';
2
+ export function isMediaSeekable(media) {
3
+ return getTimeRangeDuration(media.seekable) > 0;
4
+ }