@cloudnest/redxplyr 1.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.
- package/.editorconfig +10 -0
- package/.gitpod.yml +6 -0
- package/.node-version +1 -0
- package/.prettierrc +7 -0
- package/.stickler.yml +5 -0
- package/.stylelintrc.json +26 -0
- package/CHANGELOG.md +16 -0
- package/CONTRIBUTING.md +34 -0
- package/CONTROLS.md +49 -0
- package/Dockerfile +32 -0
- package/LICENSE.md +22 -0
- package/README.md +194 -0
- package/cspell.json +48 -0
- package/dist/redxplyr.css +1 -0
- package/dist/redxplyr.js +8801 -0
- package/dist/redxplyr.min.js +2 -0
- package/dist/redxplyr.min.js.map +1 -0
- package/dist/redxplyr.min.mjs +1 -0
- package/dist/redxplyr.min.mjs.map +1 -0
- package/dist/redxplyr.mjs +8793 -0
- package/dist/redxplyr.polyfilled.js +9294 -0
- package/dist/redxplyr.polyfilled.min.js +2 -0
- package/dist/redxplyr.polyfilled.min.js.map +1 -0
- package/dist/redxplyr.polyfilled.min.mjs +1 -0
- package/dist/redxplyr.polyfilled.min.mjs.map +1 -0
- package/dist/redxplyr.polyfilled.mjs +9286 -0
- package/dist/redxplyr.svg +1 -0
- package/eslint.config.mjs +39 -0
- package/gulpfile.js +8 -0
- package/package.json +114 -0
- package/pnpm-workspace.yaml +8 -0
- package/src/js/captions.js +411 -0
- package/src/js/config/defaults.js +459 -0
- package/src/js/config/states.js +10 -0
- package/src/js/config/types.js +34 -0
- package/src/js/console.js +28 -0
- package/src/js/controls.js +1870 -0
- package/src/js/fullscreen.js +305 -0
- package/src/js/html5.js +148 -0
- package/src/js/listeners.js +854 -0
- package/src/js/media.js +61 -0
- package/src/js/plugins/ads.js +647 -0
- package/src/js/plugins/preview-thumbnails.js +706 -0
- package/src/js/plugins/vimeo.js +443 -0
- package/src/js/plugins/youtube.js +451 -0
- package/src/js/plyr.d.ts +729 -0
- package/src/js/plyr.js +1291 -0
- package/src/js/plyr.polyfilled.js +13 -0
- package/src/js/source.js +155 -0
- package/src/js/storage.js +70 -0
- package/src/js/support.js +100 -0
- package/src/js/ui.js +297 -0
- package/src/js/utils/animation.js +33 -0
- package/src/js/utils/arrays.js +23 -0
- package/src/js/utils/browser.js +21 -0
- package/src/js/utils/elements.js +263 -0
- package/src/js/utils/events.js +116 -0
- package/src/js/utils/fetch.js +45 -0
- package/src/js/utils/i18n.js +47 -0
- package/src/js/utils/is.js +81 -0
- package/src/js/utils/load-image.js +19 -0
- package/src/js/utils/load-script.js +14 -0
- package/src/js/utils/load-sprite.js +77 -0
- package/src/js/utils/numbers.js +17 -0
- package/src/js/utils/objects.js +43 -0
- package/src/js/utils/promise.js +14 -0
- package/src/js/utils/strings.js +80 -0
- package/src/js/utils/style.js +148 -0
- package/src/js/utils/time.js +36 -0
- package/src/js/utils/urls.js +40 -0
- package/src/sass/base.scss +69 -0
- package/src/sass/components/badges.scss +12 -0
- package/src/sass/components/captions.scss +58 -0
- package/src/sass/components/control.scss +52 -0
- package/src/sass/components/controls.scss +65 -0
- package/src/sass/components/menus.scss +205 -0
- package/src/sass/components/poster.scss +27 -0
- package/src/sass/components/progress.scss +107 -0
- package/src/sass/components/sliders.scss +99 -0
- package/src/sass/components/times.scss +20 -0
- package/src/sass/components/tooltips.scss +91 -0
- package/src/sass/components/volume.scss +18 -0
- package/src/sass/lib/animation.scss +31 -0
- package/src/sass/lib/css-vars.scss +103 -0
- package/src/sass/lib/functions.scss +3 -0
- package/src/sass/lib/mixins.scss +82 -0
- package/src/sass/plugins/ads.scss +53 -0
- package/src/sass/plugins/preview-thumbnails/index.scss +121 -0
- package/src/sass/plugins/preview-thumbnails/settings.scss +17 -0
- package/src/sass/plyr.scss +46 -0
- package/src/sass/settings/badges.scss +7 -0
- package/src/sass/settings/breakpoints.scss +9 -0
- package/src/sass/settings/captions.scss +10 -0
- package/src/sass/settings/colors.scss +18 -0
- package/src/sass/settings/controls.scss +30 -0
- package/src/sass/settings/cosmetics.scss +5 -0
- package/src/sass/settings/helpers.scss +7 -0
- package/src/sass/settings/menus.scss +13 -0
- package/src/sass/settings/progress.scss +18 -0
- package/src/sass/settings/sliders.scss +39 -0
- package/src/sass/settings/tooltips.scss +11 -0
- package/src/sass/settings/type.scss +16 -0
- package/src/sass/states/fullscreen.scss +15 -0
- package/src/sass/types/audio.scss +61 -0
- package/src/sass/types/video.scss +170 -0
- package/src/sass/utils/animation.scss +7 -0
- package/src/sass/utils/hidden.scss +28 -0
- package/src/sprite/plyr-airplay.svg +8 -0
- package/src/sprite/plyr-captions-off.svg +7 -0
- package/src/sprite/plyr-captions-on.svg +7 -0
- package/src/sprite/plyr-download.svg +8 -0
- package/src/sprite/plyr-enter-fullscreen.svg +4 -0
- package/src/sprite/plyr-exit-fullscreen.svg +4 -0
- package/src/sprite/plyr-fast-forward.svg +3 -0
- package/src/sprite/plyr-logo-vimeo.svg +6 -0
- package/src/sprite/plyr-logo-youtube.svg +6 -0
- package/src/sprite/plyr-muted.svg +8 -0
- package/src/sprite/plyr-pause.svg +8 -0
- package/src/sprite/plyr-pip.svg +6 -0
- package/src/sprite/plyr-play.svg +5 -0
- package/src/sprite/plyr-restart.svg +5 -0
- package/src/sprite/plyr-rewind.svg +3 -0
- package/src/sprite/plyr-settings.svg +5 -0
- package/src/sprite/plyr-volume.svg +11 -0
- package/tasks/build.js +226 -0
- package/tasks/deploy.js +216 -0
- package/tasks/utils/publish.js +34 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// Fullscreen wrapper
|
|
3
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API#prefixing
|
|
4
|
+
// https://webkit.org/blog/7929/designing-websites-for-iphone-x/
|
|
5
|
+
// ==========================================================================
|
|
6
|
+
|
|
7
|
+
import browser from './utils/browser';
|
|
8
|
+
import { closest, getElements, hasClass, toggleClass } from './utils/elements';
|
|
9
|
+
import { on, triggerEvent } from './utils/events';
|
|
10
|
+
import is from './utils/is';
|
|
11
|
+
import { silencePromise } from './utils/promise';
|
|
12
|
+
|
|
13
|
+
class Fullscreen {
|
|
14
|
+
constructor(player) {
|
|
15
|
+
// Keep reference to parent
|
|
16
|
+
this.player = player;
|
|
17
|
+
|
|
18
|
+
// Get prefix
|
|
19
|
+
this.prefix = Fullscreen.prefix;
|
|
20
|
+
this.property = Fullscreen.property;
|
|
21
|
+
|
|
22
|
+
// Scroll position
|
|
23
|
+
this.scrollPosition = { x: 0, y: 0 };
|
|
24
|
+
|
|
25
|
+
// Force the use of 'full window/browser' rather than fullscreen
|
|
26
|
+
this.forceFallback = player.config.fullscreen.fallback === 'force';
|
|
27
|
+
|
|
28
|
+
// Get the fullscreen element
|
|
29
|
+
// Checks container is an ancestor, defaults to null
|
|
30
|
+
this.player.elements.fullscreen
|
|
31
|
+
= player.config.fullscreen.container && closest(this.player.elements.container, player.config.fullscreen.container);
|
|
32
|
+
|
|
33
|
+
// Register event listeners
|
|
34
|
+
// Handle event (incase user presses escape etc)
|
|
35
|
+
on.call(
|
|
36
|
+
this.player,
|
|
37
|
+
document,
|
|
38
|
+
this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`,
|
|
39
|
+
() => {
|
|
40
|
+
// TODO: Filter for target??
|
|
41
|
+
this.onChange();
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Fullscreen toggle on double click
|
|
46
|
+
on.call(this.player, this.player.elements.container, 'dblclick', (event) => {
|
|
47
|
+
// Ignore double click in controls
|
|
48
|
+
if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.player.listeners.proxy(event, this.toggle, 'fullscreen');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Tap focus when in fullscreen
|
|
56
|
+
on.call(this, this.player.elements.container, 'keydown', event => this.trapFocus(event));
|
|
57
|
+
|
|
58
|
+
// Update the UI
|
|
59
|
+
this.update();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Determine if native supported
|
|
63
|
+
static get nativeSupported() {
|
|
64
|
+
return !!(
|
|
65
|
+
document.fullscreenEnabled
|
|
66
|
+
|| document.webkitFullscreenEnabled
|
|
67
|
+
|| document.mozFullScreenEnabled
|
|
68
|
+
|| document.msFullscreenEnabled
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// If we're actually using native
|
|
73
|
+
get useNative() {
|
|
74
|
+
return Fullscreen.nativeSupported && !this.forceFallback;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Get the prefix for handlers
|
|
78
|
+
static get prefix() {
|
|
79
|
+
// No prefix
|
|
80
|
+
if (is.function(document.exitFullscreen)) return '';
|
|
81
|
+
|
|
82
|
+
// Check for fullscreen support by vendor prefix
|
|
83
|
+
let value = '';
|
|
84
|
+
const prefixes = ['webkit', 'moz', 'ms'];
|
|
85
|
+
|
|
86
|
+
prefixes.some((pre) => {
|
|
87
|
+
if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) {
|
|
88
|
+
value = pre;
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return false;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static get property() {
|
|
99
|
+
return this.prefix === 'moz' ? 'FullScreen' : 'Fullscreen';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Determine if fullscreen is supported
|
|
103
|
+
get supported() {
|
|
104
|
+
return [
|
|
105
|
+
// Fullscreen is enabled in config
|
|
106
|
+
this.player.config.fullscreen.enabled,
|
|
107
|
+
// Must be a video
|
|
108
|
+
this.player.isVideo,
|
|
109
|
+
// Either native is supported or fallback enabled
|
|
110
|
+
Fullscreen.nativeSupported || this.player.config.fullscreen.fallback,
|
|
111
|
+
// YouTube has no way to trigger fullscreen, so on devices with no native support, playsinline
|
|
112
|
+
// must be enabled and iosNative fullscreen must be disabled to offer the fullscreen fallback
|
|
113
|
+
!this.player.isYouTube
|
|
114
|
+
|| Fullscreen.nativeSupported
|
|
115
|
+
|| !browser.isIos
|
|
116
|
+
|| (this.player.config.playsinline && !this.player.config.fullscreen.iosNative),
|
|
117
|
+
].every(Boolean);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Get active state
|
|
121
|
+
get active() {
|
|
122
|
+
if (!this.supported) return false;
|
|
123
|
+
|
|
124
|
+
// Fallback using classname
|
|
125
|
+
if (!Fullscreen.nativeSupported || this.forceFallback) {
|
|
126
|
+
return hasClass(this.target, this.player.config.classNames.fullscreen.fallback);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const element = !this.prefix
|
|
130
|
+
? this.target.getRootNode().fullscreenElement
|
|
131
|
+
: this.target.getRootNode()[`${this.prefix}${this.property}Element`];
|
|
132
|
+
|
|
133
|
+
return element && element.shadowRoot ? element === this.target.getRootNode().host : element === this.target;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Get target element
|
|
137
|
+
get target() {
|
|
138
|
+
return browser.isIos && this.player.config.fullscreen.iosNative
|
|
139
|
+
? this.player.media
|
|
140
|
+
: this.player.elements.fullscreen ?? this.player.elements.container;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
onChange = () => {
|
|
144
|
+
if (!this.supported) return;
|
|
145
|
+
|
|
146
|
+
// Update toggle button
|
|
147
|
+
const button = this.player.elements.buttons.fullscreen;
|
|
148
|
+
if (is.element(button)) {
|
|
149
|
+
button.pressed = this.active;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up
|
|
153
|
+
const target = this.target === this.player.media ? this.target : this.player.elements.container;
|
|
154
|
+
// Trigger an event
|
|
155
|
+
triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
toggleFallback = (toggle = false) => {
|
|
159
|
+
// Store or restore scroll position
|
|
160
|
+
if (toggle) {
|
|
161
|
+
this.scrollPosition = {
|
|
162
|
+
x: window.scrollX ?? 0,
|
|
163
|
+
y: window.scrollY ?? 0,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Toggle scroll
|
|
171
|
+
document.body.style.overflow = toggle ? 'hidden' : '';
|
|
172
|
+
|
|
173
|
+
// Toggle class hook
|
|
174
|
+
toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);
|
|
175
|
+
|
|
176
|
+
// Force full viewport on iPhone X+
|
|
177
|
+
if (browser.isIos) {
|
|
178
|
+
let viewport = document.head.querySelector('meta[name="viewport"]');
|
|
179
|
+
const property = 'viewport-fit=cover';
|
|
180
|
+
|
|
181
|
+
// Inject the viewport meta if required
|
|
182
|
+
if (!viewport) {
|
|
183
|
+
viewport = document.createElement('meta');
|
|
184
|
+
viewport.setAttribute('name', 'viewport');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check if the property already exists
|
|
188
|
+
const hasProperty = is.string(viewport.content) && viewport.content.includes(property);
|
|
189
|
+
|
|
190
|
+
if (toggle) {
|
|
191
|
+
this.cleanupViewport = !hasProperty;
|
|
192
|
+
if (!hasProperty) viewport.content += `,${property}`;
|
|
193
|
+
}
|
|
194
|
+
else if (this.cleanupViewport) {
|
|
195
|
+
viewport.content = viewport.content
|
|
196
|
+
.split(',')
|
|
197
|
+
.filter(part => part.trim() !== property)
|
|
198
|
+
.join(',');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Toggle button and fire events
|
|
203
|
+
this.onChange();
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Trap focus inside container
|
|
207
|
+
trapFocus = (event) => {
|
|
208
|
+
// Bail if iOS/iPadOS, not active, not the tab key
|
|
209
|
+
if (browser.isIos || browser.isIPadOS || !this.active || event.key !== 'Tab') return;
|
|
210
|
+
|
|
211
|
+
// Get the current focused element
|
|
212
|
+
const focused = document.activeElement;
|
|
213
|
+
const focusable = getElements.call(this.player, 'a[href], button:not(:disabled), input:not(:disabled), [tabindex]');
|
|
214
|
+
const [first] = focusable;
|
|
215
|
+
const last = focusable[focusable.length - 1];
|
|
216
|
+
|
|
217
|
+
if (focused === last && !event.shiftKey) {
|
|
218
|
+
// Move focus to first element that can be tabbed if Shift isn't used
|
|
219
|
+
first.focus();
|
|
220
|
+
event.preventDefault();
|
|
221
|
+
}
|
|
222
|
+
else if (focused === first && event.shiftKey) {
|
|
223
|
+
// Move focus to last element that can be tabbed if Shift is used
|
|
224
|
+
last.focus();
|
|
225
|
+
event.preventDefault();
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// Update UI
|
|
230
|
+
update = () => {
|
|
231
|
+
if (this.supported) {
|
|
232
|
+
let mode;
|
|
233
|
+
|
|
234
|
+
if (this.forceFallback) mode = 'Fallback (forced)';
|
|
235
|
+
else if (Fullscreen.nativeSupported) mode = 'Native';
|
|
236
|
+
else mode = 'Fallback';
|
|
237
|
+
|
|
238
|
+
this.player.debug.log(`${mode} fullscreen enabled`);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
this.player.debug.log('Fullscreen not supported and fallback disabled');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Add styling hook to show button
|
|
245
|
+
toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.supported);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// Make an element fullscreen
|
|
249
|
+
enter = () => {
|
|
250
|
+
if (!this.supported) return;
|
|
251
|
+
|
|
252
|
+
// iOS native fullscreen doesn't need the request step
|
|
253
|
+
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
|
254
|
+
if (this.player.isVimeo) {
|
|
255
|
+
this.player.embed.requestFullscreen();
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
this.target.webkitEnterFullscreen();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else if (!Fullscreen.nativeSupported || this.forceFallback) {
|
|
262
|
+
this.toggleFallback(true);
|
|
263
|
+
}
|
|
264
|
+
else if (!this.prefix) {
|
|
265
|
+
this.target.requestFullscreen({ navigationUI: 'hide' });
|
|
266
|
+
}
|
|
267
|
+
else if (!is.empty(this.prefix)) {
|
|
268
|
+
this.target[`${this.prefix}Request${this.property}`]();
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Bail from fullscreen
|
|
273
|
+
exit = () => {
|
|
274
|
+
if (!this.supported) return;
|
|
275
|
+
|
|
276
|
+
// iOS native fullscreen
|
|
277
|
+
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
|
278
|
+
if (this.player.isVimeo) {
|
|
279
|
+
this.player.embed.exitFullscreen();
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
this.target.webkitEnterFullscreen();
|
|
283
|
+
}
|
|
284
|
+
silencePromise(this.player.play());
|
|
285
|
+
}
|
|
286
|
+
else if (!Fullscreen.nativeSupported || this.forceFallback) {
|
|
287
|
+
this.toggleFallback(false);
|
|
288
|
+
}
|
|
289
|
+
else if (!this.prefix) {
|
|
290
|
+
(document.cancelFullScreen || document.exitFullscreen).call(document);
|
|
291
|
+
}
|
|
292
|
+
else if (!is.empty(this.prefix)) {
|
|
293
|
+
const action = this.prefix === 'moz' ? 'Cancel' : 'Exit';
|
|
294
|
+
document[`${this.prefix}${action}${this.property}`]();
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// Toggle state
|
|
299
|
+
toggle = () => {
|
|
300
|
+
if (!this.active) this.enter();
|
|
301
|
+
else this.exit();
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export default Fullscreen;
|
package/src/js/html5.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// Plyr HTML5 helpers
|
|
3
|
+
// ==========================================================================
|
|
4
|
+
|
|
5
|
+
import support from './support';
|
|
6
|
+
import { removeElement } from './utils/elements';
|
|
7
|
+
import { triggerEvent } from './utils/events';
|
|
8
|
+
import is from './utils/is';
|
|
9
|
+
import { silencePromise } from './utils/promise';
|
|
10
|
+
import { setAspectRatio } from './utils/style';
|
|
11
|
+
|
|
12
|
+
const html5 = {
|
|
13
|
+
getSources() {
|
|
14
|
+
if (!this.isHTML5) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const sources = Array.from(this.media.querySelectorAll('source'));
|
|
19
|
+
|
|
20
|
+
// Filter out unsupported sources (if type is specified)
|
|
21
|
+
return sources.filter((source) => {
|
|
22
|
+
const type = source.getAttribute('type');
|
|
23
|
+
|
|
24
|
+
if (is.empty(type)) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return support.mime.call(this, type);
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// Get quality levels
|
|
33
|
+
getQualityOptions() {
|
|
34
|
+
// Whether we're forcing all options (e.g. for streaming)
|
|
35
|
+
if (this.config.quality.forced) {
|
|
36
|
+
return this.config.quality.options;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Get sizes from <source> elements
|
|
40
|
+
return html5.getSources
|
|
41
|
+
.call(this)
|
|
42
|
+
.map(source => Number(source.getAttribute('size')))
|
|
43
|
+
.filter(Boolean);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
setup() {
|
|
47
|
+
if (!this.isHTML5) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const player = this;
|
|
52
|
+
|
|
53
|
+
// Set speed options from config
|
|
54
|
+
player.options.speed = player.config.speed.options;
|
|
55
|
+
|
|
56
|
+
// Set aspect ratio if fixed
|
|
57
|
+
if (!is.empty(this.config.ratio)) {
|
|
58
|
+
setAspectRatio.call(player);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Quality
|
|
62
|
+
Object.defineProperty(player.media, 'quality', {
|
|
63
|
+
get() {
|
|
64
|
+
// Get sources
|
|
65
|
+
const sources = html5.getSources.call(player);
|
|
66
|
+
const source = sources.find(s => s.getAttribute('src') === player.source);
|
|
67
|
+
|
|
68
|
+
// Return size, if match is found
|
|
69
|
+
return source && Number(source.getAttribute('size'));
|
|
70
|
+
},
|
|
71
|
+
set(input) {
|
|
72
|
+
if (player.quality === input) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// If we're using an external handler...
|
|
77
|
+
if (player.config.quality.forced && is.function(player.config.quality.onChange)) {
|
|
78
|
+
player.config.quality.onChange(input);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Get sources
|
|
82
|
+
const sources = html5.getSources.call(player);
|
|
83
|
+
// Get first match for requested size
|
|
84
|
+
const source = sources.find(s => Number(s.getAttribute('size')) === input);
|
|
85
|
+
|
|
86
|
+
// No matching source found
|
|
87
|
+
if (!source) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Get current state
|
|
92
|
+
const { currentTime, paused, preload, readyState, playbackRate } = player.media;
|
|
93
|
+
|
|
94
|
+
// Set new source
|
|
95
|
+
player.media.src = source.getAttribute('src');
|
|
96
|
+
|
|
97
|
+
// Prevent loading if preload="none" and the current source isn't loaded (#1044)
|
|
98
|
+
if (preload !== 'none' || readyState) {
|
|
99
|
+
// Restore time
|
|
100
|
+
player.once('loadedmetadata', () => {
|
|
101
|
+
player.speed = playbackRate;
|
|
102
|
+
player.currentTime = currentTime;
|
|
103
|
+
|
|
104
|
+
// Resume playing
|
|
105
|
+
if (!paused) {
|
|
106
|
+
silencePromise(player.play());
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Load new source
|
|
111
|
+
player.media.load();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Trigger change event
|
|
116
|
+
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
|
117
|
+
quality: input,
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// Cancel current network requests
|
|
124
|
+
// See https://github.com/xgauravyaduvanshii/redxplyr/issues/174
|
|
125
|
+
cancelRequests() {
|
|
126
|
+
if (!this.isHTML5) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Remove child sources
|
|
131
|
+
removeElement(html5.getSources.call(this));
|
|
132
|
+
|
|
133
|
+
// Set blank video src attribute
|
|
134
|
+
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
|
|
135
|
+
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
|
|
136
|
+
this.media.setAttribute('src', this.config.blankVideo);
|
|
137
|
+
|
|
138
|
+
// Load the new empty source
|
|
139
|
+
// This will cancel existing requests
|
|
140
|
+
// See https://github.com/xgauravyaduvanshii/redxplyr/issues/174
|
|
141
|
+
this.media.load();
|
|
142
|
+
|
|
143
|
+
// Debugging
|
|
144
|
+
this.debug.log('Cancelled network requests');
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export default html5;
|