@capgo/capacitor-video-player 7.0.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 (70) hide show
  1. package/CapgoCapacitorVideoPlayer.podspec +17 -0
  2. package/Package.swift +28 -0
  3. package/README.md +431 -0
  4. package/android/build.gradle +72 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/java/com/capgo/videoplayer/FullscreenExoPlayerFragment.java +1406 -0
  7. package/android/src/main/java/com/capgo/videoplayer/Notifications/MyRunnable.java +21 -0
  8. package/android/src/main/java/com/capgo/videoplayer/Notifications/NotificationCenter.java +61 -0
  9. package/android/src/main/java/com/capgo/videoplayer/PickerVideo/AdapterVideoList.java +47 -0
  10. package/android/src/main/java/com/capgo/videoplayer/PickerVideo/ModelVideo.java +49 -0
  11. package/android/src/main/java/com/capgo/videoplayer/PickerVideo/PickerVideoFragment.java +116 -0
  12. package/android/src/main/java/com/capgo/videoplayer/PickerVideo/VideoRecyclerViewHolder.java +65 -0
  13. package/android/src/main/java/com/capgo/videoplayer/Utilities/FilesUtils.java +38 -0
  14. package/android/src/main/java/com/capgo/videoplayer/Utilities/FragmentUtils.java +32 -0
  15. package/android/src/main/java/com/capgo/videoplayer/VideoPlayer.java +71 -0
  16. package/android/src/main/java/com/capgo/videoplayer/VideoPlayerPlugin.java +1239 -0
  17. package/android/src/main/res/.gitkeep +0 -0
  18. package/android/src/main/res/drawable/bg_round_rect_white_50.xml +9 -0
  19. package/android/src/main/res/drawable/bg_rounded_rectangle_white_corner_rounded.xml +10 -0
  20. package/android/src/main/res/drawable/exo_close_btn.xml +12 -0
  21. package/android/src/main/res/drawable/gradient_transparent_middle.xml +12 -0
  22. package/android/src/main/res/drawable/ic_arrow_left.xml +5 -0
  23. package/android/src/main/res/drawable/ic_baseline_lq.xml +7 -0
  24. package/android/src/main/res/drawable/ic_exo_icon_fastforward.xml +35 -0
  25. package/android/src/main/res/drawable/ic_exo_icon_pause.xml +26 -0
  26. package/android/src/main/res/drawable/ic_exo_icon_play.xml +36 -0
  27. package/android/src/main/res/drawable/ic_exo_icon_rewind.xml +35 -0
  28. package/android/src/main/res/drawable/ic_expand.xml +5 -0
  29. package/android/src/main/res/drawable/ic_fit.xml +5 -0
  30. package/android/src/main/res/drawable/ic_image_background.xml +12 -0
  31. package/android/src/main/res/drawable/ic_img_16_9_background.xml +10 -0
  32. package/android/src/main/res/drawable/ic_img_9_16_background.xml +10 -0
  33. package/android/src/main/res/drawable/ic_outline_lock.xml +5 -0
  34. package/android/src/main/res/drawable/ic_outline_lock_open.xml +5 -0
  35. package/android/src/main/res/drawable/ic_pip_white.xml +5 -0
  36. package/android/src/main/res/drawable/ic_views.xml +18 -0
  37. package/android/src/main/res/drawable/ic_zoom.xml +5 -0
  38. package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
  39. package/android/src/main/res/layout/exo_playback_control_view.xml +287 -0
  40. package/android/src/main/res/layout/exoplayer_layout_youtube.xml +361 -0
  41. package/android/src/main/res/layout/fragment_fs_exoplayer.xml +50 -0
  42. package/android/src/main/res/layout/fragment_picker_video.xml +21 -0
  43. package/android/src/main/res/layout/row_video.xml +76 -0
  44. package/android/src/main/res/values/colors.xml +14 -0
  45. package/android/src/main/res/values/strings.xml +3 -0
  46. package/android/src/main/res/values/styles.xml +3 -0
  47. package/dist/docs.json +686 -0
  48. package/dist/esm/definitions.d.ts +307 -0
  49. package/dist/esm/definitions.js +2 -0
  50. package/dist/esm/definitions.js.map +1 -0
  51. package/dist/esm/index.d.ts +4 -0
  52. package/dist/esm/index.js +7 -0
  53. package/dist/esm/index.js.map +1 -0
  54. package/dist/esm/web-utils/video-types.d.ts +4 -0
  55. package/dist/esm/web-utils/video-types.js +9 -0
  56. package/dist/esm/web-utils/video-types.js.map +1 -0
  57. package/dist/esm/web-utils/videoplayer.d.ts +30 -0
  58. package/dist/esm/web-utils/videoplayer.js +323 -0
  59. package/dist/esm/web-utils/videoplayer.js.map +1 -0
  60. package/dist/esm/web.d.ts +121 -0
  61. package/dist/esm/web.js +675 -0
  62. package/dist/esm/web.js.map +1 -0
  63. package/dist/plugin.cjs.js +1019 -0
  64. package/dist/plugin.cjs.js.map +1 -0
  65. package/dist/plugin.js +1021 -0
  66. package/dist/plugin.js.map +1 -0
  67. package/ios/Sources/VideoPlayerPlugin/VideoPlayer.swift +8 -0
  68. package/ios/Sources/VideoPlayerPlugin/VideoPlayerPlugin.swift +23 -0
  69. package/ios/Tests/VideoPlayerPluginTests/VideoPlayerPluginTests.swift +15 -0
  70. package/package.json +85 -0
@@ -0,0 +1,323 @@
1
+ import Hls from 'hls.js';
2
+ import { videoTypes, possibleQueryParameterExtensions } from './video-types';
3
+ export class VideoPlayer {
4
+ constructor(mode, url, playerId, rate, exitOnEnd, loopOnEnd, container, zIndex, width, height) {
5
+ this.pipMode = false;
6
+ this._videoType = null;
7
+ this._videoContainer = null;
8
+ this._firstReadyToPlay = true;
9
+ this._isEnded = false;
10
+ this._videoRate = 1.0;
11
+ this._videoExitOnEnd = true;
12
+ this._videoLoopOnEnd = false;
13
+ this._url = url;
14
+ this._container = container;
15
+ this._mode = mode;
16
+ this._width = width ? width : 320;
17
+ this._height = height ? height : 180;
18
+ this._mode = mode;
19
+ this._videoRate = rate;
20
+ this._zIndex = zIndex ? zIndex : 1;
21
+ this._playerId = playerId;
22
+ this._videoExitOnEnd = exitOnEnd;
23
+ this._videoLoopOnEnd = loopOnEnd;
24
+ }
25
+ async initialize() {
26
+ // get the video type
27
+ const urlVideoType = this._getVideoType();
28
+ if (urlVideoType) {
29
+ // style the container
30
+ if (this._mode === 'fullscreen') {
31
+ this._container.style.position = 'absolute';
32
+ this._container.style.width = '100vw';
33
+ this._container.style.height = '100vh';
34
+ }
35
+ if (this._mode === 'embedded') {
36
+ this._container.style.position = 'relative';
37
+ this._container.style.width = this._width.toString() + 'px';
38
+ this._container.style.height = this._height.toString() + 'px';
39
+ }
40
+ this._container.style.left = '0';
41
+ this._container.style.top = '0';
42
+ this._container.style.display = 'flex';
43
+ this._container.style.alignItems = 'center';
44
+ this._container.style.justifyContent = 'center';
45
+ this._container.style.backgroundColor = '#000000';
46
+ this._container.style.zIndex = this._zIndex.toString();
47
+ const width = this._mode === 'fullscreen' ? window.innerWidth /*this._container.offsetWidth*/ : this._width;
48
+ const height = this._mode === 'fullscreen' ? window.innerHeight /*this._container.offsetHeight*/ : this._height;
49
+ const xmlns = 'http://www.w3.org/2000/svg';
50
+ const svg = document.createElementNS(xmlns, 'svg');
51
+ svg.setAttributeNS(null, 'width', width.toString());
52
+ svg.setAttributeNS(null, 'height', height.toString());
53
+ const viewbox = '0 0 ' + width.toString() + ' ' + height.toString();
54
+ svg.setAttributeNS(null, 'viewBox', viewbox);
55
+ svg.style.zIndex = (this._zIndex + 1).toString();
56
+ const rect = document.createElementNS(xmlns, 'rect');
57
+ rect.setAttributeNS(null, 'x', '0');
58
+ rect.setAttributeNS(null, 'y', '0');
59
+ rect.setAttributeNS(null, 'width', width.toString());
60
+ rect.setAttributeNS(null, 'height', height.toString());
61
+ rect.setAttributeNS(null, 'fill', '#000000');
62
+ svg.appendChild(rect);
63
+ this._container.appendChild(svg);
64
+ const heightVideo = (width * this._height) / this._width;
65
+ this._videoContainer = document.createElement('div');
66
+ this._videoContainer.style.position = 'absolute';
67
+ this._videoContainer.style.left = '0';
68
+ this._videoContainer.style.width = width.toString() + 'px';
69
+ this._videoContainer.style.height = heightVideo.toString() + 'px';
70
+ this._videoContainer.style.zIndex = (this._zIndex + 2).toString();
71
+ this._container.appendChild(this._videoContainer);
72
+ /* Create Video Element */
73
+ const isCreated = await this.createVideoElement(width, heightVideo);
74
+ if (!isCreated) {
75
+ this._createEvent('Exit', this._playerId, 'Video Error: failed to create the Video Element');
76
+ }
77
+ }
78
+ else {
79
+ this._createEvent('Exit', this._playerId, 'Url Error: type not supported');
80
+ }
81
+ return;
82
+ }
83
+ async createVideoElement(width, height) {
84
+ this.videoEl = document.createElement('video');
85
+ this.videoEl.controls = true;
86
+ this.videoEl.style.zIndex = (this._zIndex + 3).toString();
87
+ this.videoEl.style.width = `${width.toString()}px`;
88
+ this.videoEl.style.height = `${height.toString()}px`;
89
+ this.videoEl.playbackRate = this._videoRate;
90
+ this._videoContainer.appendChild(this.videoEl);
91
+ // set the player
92
+ const isSet = await this._setPlayer();
93
+ if (isSet) {
94
+ this.videoEl.onended = async () => {
95
+ this._isEnded = true;
96
+ this.isPlaying = false;
97
+ if (this.videoEl) {
98
+ this.videoEl.currentTime = 0;
99
+ }
100
+ if (this._videoExitOnEnd) {
101
+ if (this._mode === 'fullscreen') {
102
+ this._closeFullscreen();
103
+ }
104
+ this._createEvent('Ended', this._playerId);
105
+ }
106
+ else {
107
+ if (this._videoLoopOnEnd && this.videoEl != null) {
108
+ await this.videoEl.play();
109
+ }
110
+ }
111
+ };
112
+ this.videoEl.oncanplay = async () => {
113
+ if (this._firstReadyToPlay) {
114
+ this._createEvent('Ready', this._playerId);
115
+ if (this.videoEl != null) {
116
+ this.videoEl.muted = false;
117
+ if (this._mode === 'fullscreen')
118
+ await this.videoEl.play();
119
+ this._firstReadyToPlay = false;
120
+ }
121
+ }
122
+ };
123
+ this.videoEl.onplay = () => {
124
+ this.isPlaying = true;
125
+ if (this._firstReadyToPlay)
126
+ this._firstReadyToPlay = false;
127
+ this._createEvent('Play', this._playerId);
128
+ };
129
+ this.videoEl.onplaying = () => {
130
+ this._createEvent('Playing', this._playerId);
131
+ };
132
+ this.videoEl.onpause = () => {
133
+ this.isPlaying = false;
134
+ this._createEvent('Pause', this._playerId);
135
+ };
136
+ if (this._mode === 'fullscreen') {
137
+ // create the video player exit button
138
+ const exitEl = document.createElement('button');
139
+ exitEl.textContent = 'X';
140
+ exitEl.style.position = 'absolute';
141
+ exitEl.style.left = '1%';
142
+ exitEl.style.top = '5%';
143
+ exitEl.style.width = '5vmin';
144
+ exitEl.style.padding = '0.5%';
145
+ exitEl.style.fontSize = '1.2rem';
146
+ exitEl.style.background = 'rgba(51,51,51,.4)';
147
+ exitEl.style.color = '#fff';
148
+ exitEl.style.visibility = 'hidden';
149
+ exitEl.style.zIndex = (this._zIndex + 4).toString();
150
+ exitEl.style.border = '1px solid rgba(51,51,51,.4)';
151
+ exitEl.style.borderRadius = '20px';
152
+ this._videoContainer.onclick = async () => {
153
+ this._initial = await this._doHide(exitEl, 3000);
154
+ };
155
+ this._videoContainer.ontouchstart = async () => {
156
+ this._initial = await this._doHide(exitEl, 3000);
157
+ };
158
+ this._videoContainer.onmousemove = async () => {
159
+ this._initial = await this._doHide(exitEl, 3000);
160
+ };
161
+ exitEl.onclick = () => {
162
+ this._createEvent('Exit', this._playerId);
163
+ };
164
+ exitEl.ontouchstart = () => {
165
+ this._createEvent('Exit', this._playerId);
166
+ };
167
+ this._videoContainer.appendChild(exitEl);
168
+ this._initial = await this._doHide(exitEl, 3000);
169
+ this._goFullscreen();
170
+ }
171
+ }
172
+ return isSet;
173
+ }
174
+ async _goFullscreen() {
175
+ if (this._container.mozRequestFullScreen) {
176
+ /* Firefox */
177
+ this._container.mozRequestFullScreen();
178
+ }
179
+ else if (this._container.webkitRequestFullscreen) {
180
+ /* Chrome, Safari & Opera */
181
+ this._container.webkitRequestFullscreen();
182
+ }
183
+ else if (this._container.msRequestFullscreen) {
184
+ /* IE/Edge */
185
+ this._container.msRequestFullscreen();
186
+ }
187
+ else if (this._container.requestFullscreen) {
188
+ this._container.requestFullscreen();
189
+ }
190
+ return;
191
+ }
192
+ async _setPlayer() {
193
+ return new Promise((resolve) => {
194
+ if (this.videoEl != null) {
195
+ if (Hls.isSupported() && this._videoType === 'application/x-mpegURL') {
196
+ const hls = new Hls();
197
+ hls.loadSource(this._url);
198
+ hls.attachMedia(this.videoEl);
199
+ hls.once(Hls.Events.FRAG_PARSED, () => {
200
+ if (this.videoEl != null) {
201
+ this.videoEl.muted = true;
202
+ this.videoEl.crossOrigin = 'anonymous';
203
+ resolve(true);
204
+ }
205
+ else {
206
+ resolve(false);
207
+ }
208
+ });
209
+ }
210
+ else if (this._videoType === 'video/mp4') {
211
+ // CMAF (fMP4) && MP4
212
+ this.videoEl.src = this._url;
213
+ if (this._url.substring(0, 5) != 'https' && this._url.substring(0, 4) === 'http')
214
+ this.videoEl.crossOrigin = 'anonymous';
215
+ if (this._url.substring(0, 5) === 'https' || this._url.substring(0, 4) === 'http')
216
+ this.videoEl.muted = true;
217
+ resolve(true);
218
+ }
219
+ else {
220
+ // Not Supported
221
+ resolve(false);
222
+ }
223
+ this.videoEl.addEventListener('enterpictureinpicture', (event) => {
224
+ this.pipWindow = event.pictureInPictureWindow;
225
+ this.pipMode = true;
226
+ this._closeFullscreen();
227
+ });
228
+ this.videoEl.addEventListener('leavepictureinpicture', () => {
229
+ this.pipMode = false;
230
+ if (!this._isEnded) {
231
+ this._goFullscreen();
232
+ if (this.videoEl != null)
233
+ this.videoEl.play();
234
+ }
235
+ });
236
+ }
237
+ else {
238
+ resolve(false);
239
+ }
240
+ });
241
+ }
242
+ _getVideoType() {
243
+ const sUrl = this._url ? this._url : '';
244
+ if (sUrl != null && sUrl.length > 0) {
245
+ Object.entries(videoTypes).forEach(([extension, mimeType]) => {
246
+ // we search for dot + extension (e.g. `.mp4`) for URLs that have the extension in the filename
247
+ // e.g. https://vimeo.com/?file=my-video.mp4
248
+ const hasDotExtension = sUrl.match(new RegExp(`.(${extension})`, 'i'));
249
+ if (hasDotExtension) {
250
+ return (this._videoType = mimeType);
251
+ }
252
+ // we search for the extension (e.g. `m3u8`) for URLs that might have the extension as a query parameter
253
+ // e.g. https://youtube.com/?v=7894289374&type=m3u8
254
+ const hasExtensionInUrl = sUrl.match(new RegExp(`(${extension})`, 'i'));
255
+ if (hasExtensionInUrl) {
256
+ return (this._videoType = mimeType);
257
+ }
258
+ });
259
+ // we check for not supported extensions for URLs that have the extension in the filename
260
+ // e.g. https://vimeo.com/?file=not-supported-extension-video.mkv
261
+ const hasNotSupportedDotExtension = sUrl.match(/\.(.*)/i);
262
+ if (hasNotSupportedDotExtension) {
263
+ return (this._videoType = null);
264
+ }
265
+ // we check for not supported extensions for URLs that might have the extension as a query parameter
266
+ // e.g. https://youtube.com/?v=3982748927&filetype=mkv
267
+ const hasNotSupportedExtensionInUrl = sUrl.match(new RegExp(`(${possibleQueryParameterExtensions.join('|')})=+(.*)&?(?=&|$))`, 'i'));
268
+ if (hasNotSupportedExtensionInUrl) {
269
+ return (this._videoType = null);
270
+ }
271
+ // No extension found, then we assume it's 'mp4' (Match case for '')
272
+ return 'video/mp4';
273
+ }
274
+ // URL was not defined, we return null
275
+ return null;
276
+ }
277
+ async _doHide(exitEl, duration) {
278
+ clearTimeout(this._initial);
279
+ exitEl.style.visibility = 'visible';
280
+ const initial = setTimeout(() => {
281
+ exitEl.style.visibility = 'hidden';
282
+ }, duration);
283
+ return initial;
284
+ }
285
+ _createEvent(ev, playerId, msg) {
286
+ const message = msg ? msg : null;
287
+ let event;
288
+ if (message != null) {
289
+ event = new CustomEvent(`videoPlayer${ev}`, {
290
+ detail: { fromPlayerId: playerId, message: message },
291
+ });
292
+ }
293
+ else {
294
+ const currentTime = this.videoEl ? this.videoEl.currentTime : 0;
295
+ event = new CustomEvent(`videoPlayer${ev}`, {
296
+ detail: { fromPlayerId: playerId, currentTime: currentTime },
297
+ });
298
+ }
299
+ document.dispatchEvent(event);
300
+ }
301
+ _closeFullscreen() {
302
+ const mydoc = document;
303
+ const isInFullScreen = (mydoc.fullscreenElement && mydoc.fullscreenElement !== null) ||
304
+ (mydoc.webkitFullscreenElement && mydoc.webkitFullscreenElement !== null) ||
305
+ (mydoc.mozFullScreenElement && mydoc.mozFullScreenElement !== null) ||
306
+ (mydoc.msFullscreenElement && mydoc.msFullscreenElement !== null);
307
+ if (isInFullScreen) {
308
+ if (mydoc.mozCancelFullScreen) {
309
+ mydoc.mozCancelFullScreen();
310
+ }
311
+ else if (mydoc.webkitExitFullscreen) {
312
+ mydoc.webkitExitFullscreen();
313
+ }
314
+ else if (mydoc.msExitFullscreen) {
315
+ mydoc.msExitFullscreen();
316
+ }
317
+ else if (mydoc.exitFullscreen) {
318
+ mydoc.exitFullscreen();
319
+ }
320
+ }
321
+ }
322
+ }
323
+ //# sourceMappingURL=videoplayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"videoplayer.js","sourceRoot":"","sources":["../../../src/web-utils/videoplayer.ts"],"names":[],"mappings":"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","sourcesContent":["import Hls from 'hls.js';\n\nimport type { videoMimeType } from './video-types';\nimport { videoTypes, possibleQueryParameterExtensions } from './video-types';\n\nexport class VideoPlayer {\n public videoEl: HTMLVideoElement | undefined;\n public pipMode = false;\n public pipWindow: Window | undefined;\n public isPlaying: boolean | undefined;\n\n private _url: string;\n private _playerId: string;\n private _container: any;\n private _mode: string;\n private _width: number;\n private _height: number;\n private _zIndex: number;\n private _initial: any;\n private _videoType: videoMimeType | null = null;\n private _videoContainer: any = null;\n private _firstReadyToPlay = true;\n private _isEnded = false;\n private _videoRate = 1.0;\n private _videoExitOnEnd = true;\n private _videoLoopOnEnd = false;\n\n constructor(\n mode: string,\n url: string,\n playerId: string,\n rate: number,\n exitOnEnd: boolean,\n loopOnEnd: boolean,\n container: any,\n zIndex: number,\n width?: number,\n height?: number,\n ) {\n this._url = url;\n this._container = container;\n this._mode = mode;\n this._width = width ? width : 320;\n this._height = height ? height : 180;\n this._mode = mode;\n this._videoRate = rate;\n this._zIndex = zIndex ? zIndex : 1;\n this._playerId = playerId;\n this._videoExitOnEnd = exitOnEnd;\n this._videoLoopOnEnd = loopOnEnd;\n }\n\n public async initialize(): Promise<void> {\n // get the video type\n const urlVideoType: videoMimeType | null = this._getVideoType();\n if (urlVideoType) {\n // style the container\n if (this._mode === 'fullscreen') {\n this._container.style.position = 'absolute';\n this._container.style.width = '100vw';\n this._container.style.height = '100vh';\n }\n if (this._mode === 'embedded') {\n this._container.style.position = 'relative';\n this._container.style.width = this._width.toString() + 'px';\n this._container.style.height = this._height.toString() + 'px';\n }\n this._container.style.left = '0';\n this._container.style.top = '0';\n this._container.style.display = 'flex';\n this._container.style.alignItems = 'center';\n this._container.style.justifyContent = 'center';\n this._container.style.backgroundColor = '#000000';\n this._container.style.zIndex = this._zIndex.toString();\n const width: number =\n this._mode === 'fullscreen' ? window.innerWidth /*this._container.offsetWidth*/ : this._width;\n const height: number =\n this._mode === 'fullscreen' ? window.innerHeight /*this._container.offsetHeight*/ : this._height;\n const xmlns = 'http://www.w3.org/2000/svg';\n\n const svg = document.createElementNS(xmlns, 'svg');\n svg.setAttributeNS(null, 'width', width.toString());\n svg.setAttributeNS(null, 'height', height.toString());\n const viewbox = '0 0 ' + width.toString() + ' ' + height.toString();\n svg.setAttributeNS(null, 'viewBox', viewbox);\n svg.style.zIndex = (this._zIndex + 1).toString();\n const rect = document.createElementNS(xmlns, 'rect');\n rect.setAttributeNS(null, 'x', '0');\n rect.setAttributeNS(null, 'y', '0');\n rect.setAttributeNS(null, 'width', width.toString());\n rect.setAttributeNS(null, 'height', height.toString());\n rect.setAttributeNS(null, 'fill', '#000000');\n svg.appendChild(rect);\n this._container.appendChild(svg);\n\n const heightVideo: number = (width * this._height) / this._width;\n this._videoContainer = document.createElement('div');\n this._videoContainer.style.position = 'absolute';\n this._videoContainer.style.left = '0';\n this._videoContainer.style.width = width.toString() + 'px';\n this._videoContainer.style.height = heightVideo.toString() + 'px';\n this._videoContainer.style.zIndex = (this._zIndex + 2).toString();\n this._container.appendChild(this._videoContainer);\n /* Create Video Element */\n const isCreated = await this.createVideoElement(width, heightVideo);\n if (!isCreated) {\n this._createEvent('Exit', this._playerId, 'Video Error: failed to create the Video Element');\n }\n } else {\n this._createEvent('Exit', this._playerId, 'Url Error: type not supported');\n }\n return;\n }\n\n private async createVideoElement(width: number, height: number): Promise<boolean> {\n this.videoEl = document.createElement('video');\n this.videoEl.controls = true;\n this.videoEl.style.zIndex = (this._zIndex + 3).toString();\n this.videoEl.style.width = `${width.toString()}px`;\n this.videoEl.style.height = `${height.toString()}px`;\n this.videoEl.playbackRate = this._videoRate;\n this._videoContainer.appendChild(this.videoEl);\n // set the player\n const isSet: boolean = await this._setPlayer();\n if (isSet) {\n this.videoEl.onended = async () => {\n this._isEnded = true;\n this.isPlaying = false;\n if (this.videoEl) {\n this.videoEl.currentTime = 0;\n }\n if (this._videoExitOnEnd) {\n if (this._mode === 'fullscreen') {\n this._closeFullscreen();\n }\n this._createEvent('Ended', this._playerId);\n } else {\n if (this._videoLoopOnEnd && this.videoEl != null) {\n await this.videoEl.play();\n }\n }\n };\n this.videoEl.oncanplay = async () => {\n if (this._firstReadyToPlay) {\n this._createEvent('Ready', this._playerId);\n if (this.videoEl != null) {\n this.videoEl.muted = false;\n if (this._mode === 'fullscreen') await this.videoEl.play();\n this._firstReadyToPlay = false;\n }\n }\n };\n this.videoEl.onplay = () => {\n this.isPlaying = true;\n if (this._firstReadyToPlay) this._firstReadyToPlay = false;\n this._createEvent('Play', this._playerId);\n };\n this.videoEl.onplaying = () => {\n this._createEvent('Playing', this._playerId);\n };\n this.videoEl.onpause = () => {\n this.isPlaying = false;\n this._createEvent('Pause', this._playerId);\n };\n if (this._mode === 'fullscreen') {\n // create the video player exit button\n const exitEl: HTMLButtonElement = document.createElement('button');\n exitEl.textContent = 'X';\n exitEl.style.position = 'absolute';\n exitEl.style.left = '1%';\n exitEl.style.top = '5%';\n exitEl.style.width = '5vmin';\n exitEl.style.padding = '0.5%';\n exitEl.style.fontSize = '1.2rem';\n exitEl.style.background = 'rgba(51,51,51,.4)';\n exitEl.style.color = '#fff';\n exitEl.style.visibility = 'hidden';\n exitEl.style.zIndex = (this._zIndex + 4).toString();\n exitEl.style.border = '1px solid rgba(51,51,51,.4)';\n exitEl.style.borderRadius = '20px';\n this._videoContainer.onclick = async () => {\n this._initial = await this._doHide(exitEl, 3000);\n };\n this._videoContainer.ontouchstart = async () => {\n this._initial = await this._doHide(exitEl, 3000);\n };\n\n this._videoContainer.onmousemove = async () => {\n this._initial = await this._doHide(exitEl, 3000);\n };\n\n exitEl.onclick = () => {\n this._createEvent('Exit', this._playerId);\n };\n exitEl.ontouchstart = () => {\n this._createEvent('Exit', this._playerId);\n };\n\n this._videoContainer.appendChild(exitEl);\n this._initial = await this._doHide(exitEl, 3000);\n\n this._goFullscreen();\n }\n }\n return isSet;\n }\n\n private async _goFullscreen(): Promise<void> {\n if (this._container.mozRequestFullScreen) {\n /* Firefox */\n this._container.mozRequestFullScreen();\n } else if (this._container.webkitRequestFullscreen) {\n /* Chrome, Safari & Opera */\n this._container.webkitRequestFullscreen();\n } else if (this._container.msRequestFullscreen) {\n /* IE/Edge */\n this._container.msRequestFullscreen();\n } else if (this._container.requestFullscreen) {\n this._container.requestFullscreen();\n }\n return;\n }\n\n private async _setPlayer(): Promise<boolean> {\n return new Promise((resolve) => {\n if (this.videoEl != null) {\n if (Hls.isSupported() && this._videoType === 'application/x-mpegURL') {\n const hls = new Hls();\n hls.loadSource(this._url);\n hls.attachMedia(this.videoEl);\n hls.once(Hls.Events.FRAG_PARSED, () => {\n if (this.videoEl != null) {\n this.videoEl.muted = true;\n this.videoEl.crossOrigin = 'anonymous';\n resolve(true);\n } else {\n resolve(false);\n }\n });\n } else if (this._videoType === 'video/mp4') {\n // CMAF (fMP4) && MP4\n this.videoEl.src = this._url;\n if (this._url.substring(0, 5) != 'https' && this._url.substring(0, 4) === 'http')\n this.videoEl.crossOrigin = 'anonymous';\n if (this._url.substring(0, 5) === 'https' || this._url.substring(0, 4) === 'http') this.videoEl.muted = true;\n resolve(true);\n } else {\n // Not Supported\n resolve(false);\n }\n this.videoEl.addEventListener('enterpictureinpicture', (event: any) => {\n this.pipWindow = event.pictureInPictureWindow;\n this.pipMode = true;\n this._closeFullscreen();\n });\n\n this.videoEl.addEventListener('leavepictureinpicture', () => {\n this.pipMode = false;\n if (!this._isEnded) {\n this._goFullscreen();\n if (this.videoEl != null) this.videoEl.play();\n }\n });\n } else {\n resolve(false);\n }\n });\n }\n\n private _getVideoType(): videoMimeType | null {\n const sUrl: string = this._url ? this._url : '';\n if (sUrl != null && sUrl.length > 0) {\n Object.entries(videoTypes).forEach(([extension, mimeType]) => {\n // we search for dot + extension (e.g. `.mp4`) for URLs that have the extension in the filename\n // e.g. https://vimeo.com/?file=my-video.mp4\n const hasDotExtension = sUrl.match(new RegExp(`.(${extension})`, 'i'));\n if (hasDotExtension) {\n return (this._videoType = mimeType);\n }\n // we search for the extension (e.g. `m3u8`) for URLs that might have the extension as a query parameter\n // e.g. https://youtube.com/?v=7894289374&type=m3u8\n const hasExtensionInUrl = sUrl.match(new RegExp(`(${extension})`, 'i'));\n if (hasExtensionInUrl) {\n return (this._videoType = mimeType);\n }\n });\n // we check for not supported extensions for URLs that have the extension in the filename\n // e.g. https://vimeo.com/?file=not-supported-extension-video.mkv\n const hasNotSupportedDotExtension = sUrl.match(/\\.(.*)/i);\n if (hasNotSupportedDotExtension) {\n return (this._videoType = null);\n }\n // we check for not supported extensions for URLs that might have the extension as a query parameter\n // e.g. https://youtube.com/?v=3982748927&filetype=mkv\n const hasNotSupportedExtensionInUrl = sUrl.match(\n new RegExp(`(${possibleQueryParameterExtensions.join('|')})=+(.*)&?(?=&|$))`, 'i'),\n );\n if (hasNotSupportedExtensionInUrl) {\n return (this._videoType = null);\n }\n // No extension found, then we assume it's 'mp4' (Match case for '')\n return 'video/mp4';\n }\n // URL was not defined, we return null\n return null;\n }\n\n private async _doHide(exitEl: HTMLButtonElement, duration: number) {\n clearTimeout(this._initial);\n exitEl.style.visibility = 'visible';\n const initial = setTimeout(() => {\n exitEl.style.visibility = 'hidden';\n }, duration);\n return initial;\n }\n private _createEvent(ev: string, playerId: string, msg?: string) {\n const message = msg ? msg : null;\n let event: CustomEvent;\n if (message != null) {\n event = new CustomEvent(`videoPlayer${ev}`, {\n detail: { fromPlayerId: playerId, message: message },\n });\n } else {\n const currentTime: number = this.videoEl ? this.videoEl.currentTime : 0;\n event = new CustomEvent(`videoPlayer${ev}`, {\n detail: { fromPlayerId: playerId, currentTime: currentTime },\n });\n }\n document.dispatchEvent(event);\n }\n private _closeFullscreen() {\n const mydoc: any = document;\n const isInFullScreen: boolean =\n (mydoc.fullscreenElement && mydoc.fullscreenElement !== null) ||\n (mydoc.webkitFullscreenElement && mydoc.webkitFullscreenElement !== null) ||\n (mydoc.mozFullScreenElement && mydoc.mozFullScreenElement !== null) ||\n (mydoc.msFullscreenElement && mydoc.msFullscreenElement !== null);\n if (isInFullScreen) {\n if (mydoc.mozCancelFullScreen) {\n mydoc.mozCancelFullScreen();\n } else if (mydoc.webkitExitFullscreen) {\n mydoc.webkitExitFullscreen();\n } else if (mydoc.msExitFullscreen) {\n mydoc.msExitFullscreen();\n } else if (mydoc.exitFullscreen) {\n mydoc.exitFullscreen();\n }\n }\n }\n}\n"]}
@@ -0,0 +1,121 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { VideoPlayerPlugin, capEchoOptions, capVideoPlayerOptions, capVideoPlayerIdOptions, capVideoVolumeOptions, capVideoTimeOptions, capVideoMutedOptions, capVideoRateOptions, capVideoPlayerResult } from './definitions';
3
+ export interface IPlayerSize {
4
+ height: number;
5
+ width: number;
6
+ }
7
+ export declare class VideoPlayerWeb extends WebPlugin implements VideoPlayerPlugin {
8
+ private _players;
9
+ private videoContainer;
10
+ private mode;
11
+ constructor();
12
+ echo(options: capEchoOptions): Promise<capVideoPlayerResult>;
13
+ /**
14
+ * Player initialization
15
+ *
16
+ * @param options
17
+ */
18
+ initPlayer(options: capVideoPlayerOptions): Promise<capVideoPlayerResult>;
19
+ /**
20
+ * Return if a given playerId is playing
21
+ *
22
+ * @param options
23
+ */
24
+ isPlaying(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
25
+ /**
26
+ * Play the current video from a given playerId
27
+ *
28
+ * @param options
29
+ */
30
+ play(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
31
+ /**
32
+ * Pause the current video from a given playerId
33
+ *
34
+ * @param options
35
+ */
36
+ pause(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
37
+ /**
38
+ * Get the duration of the current video from a given playerId
39
+ *
40
+ * @param options
41
+ */
42
+ getDuration(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
43
+ /**
44
+ * Set the rate of the current video from a given playerId
45
+ *
46
+ * @param options
47
+ */
48
+ setRate(options: capVideoRateOptions): Promise<capVideoPlayerResult>;
49
+ /**
50
+ * Get the volume of the current video from a given playerId
51
+ *
52
+ * @param options
53
+ */
54
+ getRate(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
55
+ /**
56
+ * Set the volume of the current video from a given playerId
57
+ *
58
+ * @param options
59
+ */
60
+ setVolume(options: capVideoVolumeOptions): Promise<capVideoPlayerResult>;
61
+ /**
62
+ * Get the volume of the current video from a given playerId
63
+ *
64
+ * @param options
65
+ */
66
+ getVolume(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
67
+ /**
68
+ * Set the muted property of the current video from a given playerId
69
+ *
70
+ * @param options
71
+ */
72
+ setMuted(options: capVideoMutedOptions): Promise<capVideoPlayerResult>;
73
+ /**
74
+ * Get the muted property of the current video from a given playerId
75
+ *
76
+ * @param options
77
+ */
78
+ getMuted(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
79
+ /**
80
+ * Set the current time of the current video from a given playerId
81
+ *
82
+ * @param options
83
+ */
84
+ setCurrentTime(options: capVideoTimeOptions): Promise<capVideoPlayerResult>;
85
+ /**
86
+ * Get the current time of the current video from a given playerId
87
+ *
88
+ * @param options
89
+ */
90
+ getCurrentTime(options: capVideoPlayerIdOptions): Promise<capVideoPlayerResult>;
91
+ /**
92
+ * Get the current time of the current video from a given playerId
93
+ *
94
+ */
95
+ stopAllPlayers(): Promise<capVideoPlayerResult>;
96
+ /**
97
+ * Show controller
98
+ *
99
+ */
100
+ showController(): Promise<capVideoPlayerResult>;
101
+ /**
102
+ * isControllerIsFullyVisible
103
+ *
104
+ */
105
+ isControllerIsFullyVisible(): Promise<capVideoPlayerResult>;
106
+ /**
107
+ * Exit the current player
108
+ *
109
+ */
110
+ exitPlayer(): Promise<capVideoPlayerResult>;
111
+ private checkSize;
112
+ private _initializeVideoPlayer;
113
+ private _getContainerElement;
114
+ private handlePlayerPlay;
115
+ private handlePlayerPause;
116
+ private handlePlayerEnded;
117
+ private handlePlayerExit;
118
+ private handlePlayerReady;
119
+ private addListeners;
120
+ private removeListeners;
121
+ }