mirror of
https://github.com/videojs/video.js.git
synced 2024-11-24 08:42:25 +02:00
feat: Use userAgentData in favour of userAgent (#7979)
This commit is contained in:
parent
db4201a800
commit
2d96c9d780
@ -105,8 +105,7 @@ class Html5 extends Tech {
|
||||
// Our goal should be to get the custom controls on mobile solid everywhere
|
||||
// so we can remove this all together. Right now this will block custom
|
||||
// controls on touch enabled laptops like the Chrome Pixel
|
||||
if ((browser.TOUCH_ENABLED || browser.IS_IPHONE ||
|
||||
browser.IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) {
|
||||
if ((browser.TOUCH_ENABLED || browser.IS_IPHONE) && options.nativeControlsForTouch === true) {
|
||||
this.setControls(true);
|
||||
}
|
||||
|
||||
@ -675,10 +674,8 @@ class Html5 extends Tech {
|
||||
*/
|
||||
supportsFullScreen() {
|
||||
if (typeof this.el_.webkitEnterFullScreen === 'function') {
|
||||
const userAgent = window.navigator && window.navigator.userAgent || '';
|
||||
|
||||
// Seems to be broken in Chromium/Chrome && Safari in Leopard
|
||||
if ((/Android/).test(userAgent) || !(/Chrome|Mac OS X 10.5/).test(userAgent)) {
|
||||
// Still needed?
|
||||
if (browser.IS_ANDROID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1330,38 +1327,6 @@ Html5.prototype.featuresTimeupdateEvents = true;
|
||||
*/
|
||||
Html5.prototype.featuresVideoFrameCallback = !!(Html5.TEST_VID && Html5.TEST_VID.requestVideoFrameCallback);
|
||||
|
||||
// HTML5 Feature detection and Device Fixes --------------------------------- //
|
||||
let canPlayType;
|
||||
|
||||
Html5.patchCanPlayType = function() {
|
||||
|
||||
// Android 4.0 and above can play HLS to some extent but it reports being unable to do so
|
||||
// Firefox and Chrome report correctly
|
||||
if (browser.ANDROID_VERSION >= 4.0 && !browser.IS_FIREFOX && !browser.IS_CHROME) {
|
||||
canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
Html5.TEST_VID.constructor.prototype.canPlayType = function(type) {
|
||||
const mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i;
|
||||
|
||||
if (type && mpegurlRE.test(type)) {
|
||||
return 'maybe';
|
||||
}
|
||||
return canPlayType.call(this, type);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Html5.unpatchCanPlayType = function() {
|
||||
const r = Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
|
||||
if (canPlayType) {
|
||||
Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
// by default, patch the media element
|
||||
Html5.patchCanPlayType();
|
||||
|
||||
Html5.disposeMediaElement = function(el) {
|
||||
if (!el) {
|
||||
return;
|
||||
|
@ -5,162 +5,140 @@
|
||||
import * as Dom from './dom';
|
||||
import window from 'global/window';
|
||||
|
||||
const USER_AGENT = window.navigator && window.navigator.userAgent || '';
|
||||
const webkitVersionMap = (/AppleWebKit\/([\d.]+)/i).exec(USER_AGENT);
|
||||
const appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null;
|
||||
|
||||
/**
|
||||
* Whether or not this device is an iPod.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_IPOD = (/iPod/i).test(USER_AGENT);
|
||||
export let IS_IPOD = false;
|
||||
|
||||
/**
|
||||
* The detected iOS version - or `null`.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {string|null}
|
||||
*/
|
||||
export const IOS_VERSION = (function() {
|
||||
const match = USER_AGENT.match(/OS (\d+)_/i);
|
||||
|
||||
if (match && match[1]) {
|
||||
return match[1];
|
||||
}
|
||||
return null;
|
||||
}());
|
||||
export let IOS_VERSION = null;
|
||||
|
||||
/**
|
||||
* Whether or not this is an Android device.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_ANDROID = (/Android/i).test(USER_AGENT);
|
||||
export let IS_ANDROID = false;
|
||||
|
||||
/**
|
||||
* The detected Android version - or `null`.
|
||||
* The detected Android version - or `null` if not Android or indeterminable.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {number|string|null}
|
||||
*/
|
||||
export const ANDROID_VERSION = (function() {
|
||||
// This matches Android Major.Minor.Patch versions
|
||||
// ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
|
||||
const match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const major = match[1] && parseFloat(match[1]);
|
||||
const minor = match[2] && parseFloat(match[2]);
|
||||
|
||||
if (major && minor) {
|
||||
return parseFloat(match[1] + '.' + match[2]);
|
||||
} else if (major) {
|
||||
return major;
|
||||
}
|
||||
return null;
|
||||
}());
|
||||
|
||||
/**
|
||||
* Whether or not this is a native Android browser.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
|
||||
export let ANDROID_VERSION;
|
||||
|
||||
/**
|
||||
* Whether or not this is Mozilla Firefox.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
|
||||
export let IS_FIREFOX = false;
|
||||
|
||||
/**
|
||||
* Whether or not this is Microsoft Edge.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_EDGE = (/Edg/i).test(USER_AGENT);
|
||||
export let IS_EDGE = false;
|
||||
|
||||
/**
|
||||
* Whether or not this is Google Chrome.
|
||||
* Whether or not this is any Chromium Browser
|
||||
*
|
||||
* @static
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export let IS_CHROMIUM = false;
|
||||
|
||||
/**
|
||||
* Whether or not this is any Chromium browser that is not Edge.
|
||||
*
|
||||
* This will also be `true` for Chrome on iOS, which will have different support
|
||||
* as it is actually Safari under the hood.
|
||||
*
|
||||
* Depreacted, as the behaviour to not match Edge was to prevent Legacy Edge's UA matching.
|
||||
* IS_CHROMIUM should be used instead.
|
||||
* "Chromium but not Edge" could be explicitly tested with IS_CHROMIUM && !IS_EDGE
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @deprecated
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_CHROME = !IS_EDGE && ((/Chrome/i).test(USER_AGENT) || (/CriOS/i).test(USER_AGENT));
|
||||
export let IS_CHROME = false;
|
||||
|
||||
/**
|
||||
* The detected Chromium version - or `null`.
|
||||
*
|
||||
* @static
|
||||
* @type {number|null}
|
||||
*/
|
||||
export let CHROMIUM_VERSION = null;
|
||||
|
||||
/**
|
||||
* The detected Google Chrome version - or `null`.
|
||||
* This has always been the _Chromium_ version, i.e. would return on Chromium Edge.
|
||||
* Depreacted, use CHROMIUM_VERSION instead.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @deprecated
|
||||
* @type {number|null}
|
||||
*/
|
||||
export const CHROME_VERSION = (function() {
|
||||
const match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/);
|
||||
|
||||
if (match && match[2]) {
|
||||
return parseFloat(match[2]);
|
||||
}
|
||||
return null;
|
||||
}());
|
||||
export let CHROME_VERSION = null;
|
||||
|
||||
/**
|
||||
* The detected Internet Explorer version - or `null`.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @deprecated
|
||||
* @type {number|null}
|
||||
*/
|
||||
export const IE_VERSION = (function() {
|
||||
const result = (/MSIE\s(\d+)\.\d/).exec(USER_AGENT);
|
||||
let version = result && parseFloat(result[1]);
|
||||
|
||||
if (!version && (/Trident\/7.0/i).test(USER_AGENT) && (/rv:11.0/).test(USER_AGENT)) {
|
||||
// IE 11 has a different user agent string than other IE versions
|
||||
version = 11.0;
|
||||
}
|
||||
|
||||
return version;
|
||||
}());
|
||||
export let IE_VERSION = null;
|
||||
|
||||
/**
|
||||
* Whether or not this is desktop Safari.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_SAFARI = (/Safari/i).test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
|
||||
export let IS_SAFARI = false;
|
||||
|
||||
/**
|
||||
* Whether or not this is a Windows machine.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_WINDOWS = (/Windows/i).test(USER_AGENT);
|
||||
export let IS_WINDOWS = false;
|
||||
|
||||
/**
|
||||
* Whether or not this device is an iPad.
|
||||
*
|
||||
* @static
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export let IS_IPAD = false;
|
||||
|
||||
/**
|
||||
* Whether or not this device is an iPhone.
|
||||
*
|
||||
* @static
|
||||
* @type {Boolean}
|
||||
*/
|
||||
// The Facebook app's UIWebView identifies as both an iPhone and iPad, so
|
||||
// to identify iPhones, we need to exclude iPads.
|
||||
// http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
|
||||
export let IS_IPHONE = false;
|
||||
|
||||
/**
|
||||
* Whether or not this device is touch-enabled.
|
||||
@ -174,27 +152,98 @@ export const TOUCH_ENABLED = Boolean(Dom.isReal() && (
|
||||
window.navigator.maxTouchPoints ||
|
||||
window.DocumentTouch && window.document instanceof window.DocumentTouch));
|
||||
|
||||
/**
|
||||
* Whether or not this device is an iPad.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
export const IS_IPAD = (/iPad/i).test(USER_AGENT) ||
|
||||
const UAD = window.navigator && window.navigator.userAgentData;
|
||||
|
||||
if (UAD) {
|
||||
// If userAgentData is present, use it instead of userAgent to avoid warnings
|
||||
// Currently only implemented on Chromium
|
||||
// userAgentData does not expose Android version, so ANDROID_VERSION remains `null`
|
||||
|
||||
IS_ANDROID = UAD.platform === 'Android';
|
||||
IS_EDGE = Boolean(UAD.brands.find(b => b.brand === 'Microsoft Edge'));
|
||||
IS_CHROMIUM = Boolean(UAD.brands.find(b => b.brand === 'Chromium'));
|
||||
IS_CHROME = !IS_EDGE && IS_CHROMIUM;
|
||||
CHROMIUM_VERSION = CHROME_VERSION = (UAD.brands.find(b => b.brand === 'Chromium') || {}).version || null;
|
||||
IS_WINDOWS = UAD.platform === 'Windows';
|
||||
}
|
||||
|
||||
// If the broser is not Chromium, either userAgentData is not present which could be an old Chromium browser,
|
||||
// or it's a browser that has added userAgentData since that we don't have tests for yet. In either case,
|
||||
// the checks need to be made agiainst the regular userAgent string.
|
||||
if (!IS_CHROMIUM) {
|
||||
const USER_AGENT = window.navigator && window.navigator.userAgent || '';
|
||||
|
||||
IS_IPOD = (/iPod/i).test(USER_AGENT);
|
||||
|
||||
IOS_VERSION = (function() {
|
||||
const match = USER_AGENT.match(/OS (\d+)_/i);
|
||||
|
||||
if (match && match[1]) {
|
||||
return match[1];
|
||||
}
|
||||
return null;
|
||||
}());
|
||||
|
||||
IS_ANDROID = (/Android/i).test(USER_AGENT);
|
||||
|
||||
ANDROID_VERSION = (function() {
|
||||
// This matches Android Major.Minor.Patch versions
|
||||
// ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
|
||||
const match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const major = match[1] && parseFloat(match[1]);
|
||||
const minor = match[2] && parseFloat(match[2]);
|
||||
|
||||
if (major && minor) {
|
||||
return parseFloat(match[1] + '.' + match[2]);
|
||||
} else if (major) {
|
||||
return major;
|
||||
}
|
||||
return null;
|
||||
}());
|
||||
|
||||
IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
|
||||
|
||||
IS_EDGE = (/Edg/i).test(USER_AGENT);
|
||||
|
||||
IS_CHROMIUM = ((/Chrome/i).test(USER_AGENT) || (/CriOS/i).test(USER_AGENT));
|
||||
|
||||
IS_CHROME = !IS_EDGE && IS_CHROMIUM;
|
||||
|
||||
CHROMIUM_VERSION = CHROME_VERSION = (function() {
|
||||
const match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/);
|
||||
|
||||
if (match && match[2]) {
|
||||
return parseFloat(match[2]);
|
||||
}
|
||||
return null;
|
||||
}());
|
||||
|
||||
IE_VERSION = (function() {
|
||||
const result = (/MSIE\s(\d+)\.\d/).exec(USER_AGENT);
|
||||
let version = result && parseFloat(result[1]);
|
||||
|
||||
if (!version && (/Trident\/7.0/i).test(USER_AGENT) && (/rv:11.0/).test(USER_AGENT)) {
|
||||
// IE 11 has a different user agent string than other IE versions
|
||||
version = 11.0;
|
||||
}
|
||||
|
||||
return version;
|
||||
}());
|
||||
|
||||
IS_SAFARI = (/Safari/i).test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
|
||||
|
||||
IS_WINDOWS = (/Windows/i).test(USER_AGENT);
|
||||
|
||||
IS_IPAD = (/iPad/i).test(USER_AGENT) ||
|
||||
(IS_SAFARI && TOUCH_ENABLED && !(/iPhone/i).test(USER_AGENT));
|
||||
|
||||
/**
|
||||
* Whether or not this device is an iPhone.
|
||||
*
|
||||
* @static
|
||||
* @const
|
||||
* @type {Boolean}
|
||||
*/
|
||||
// The Facebook app's UIWebView identifies as both an iPhone and iPad, so
|
||||
// to identify iPhones, we need to exclude iPads.
|
||||
// http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
|
||||
export const IS_IPHONE = (/iPhone/i).test(USER_AGENT) && !IS_IPAD;
|
||||
IS_IPHONE = (/iPhone/i).test(USER_AGENT) && !IS_IPAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this is an iOS device.
|
||||
|
@ -218,141 +218,6 @@ QUnit.test('should remove the controls attribute when recreating the element', f
|
||||
assert.ok(player.tagAttributes.controls, 'tag attribute is still present');
|
||||
});
|
||||
|
||||
QUnit.test('patchCanPlayType patches canplaytype with our function, conditionally', function(assert) {
|
||||
// the patch runs automatically so we need to first unpatch
|
||||
Html5.unpatchCanPlayType();
|
||||
|
||||
const oldAV = browser.ANDROID_VERSION;
|
||||
const oldIsFirefox = browser.IS_FIREFOX;
|
||||
const oldIsChrome = browser.IS_CHROME;
|
||||
const video = document.createElement('video');
|
||||
const canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
|
||||
browser.stub_ANDROID_VERSION(4.0);
|
||||
browser.stub_IS_FIREFOX(false);
|
||||
browser.stub_IS_CHROME(false);
|
||||
Html5.patchCanPlayType();
|
||||
|
||||
assert.notStrictEqual(
|
||||
video.canPlayType,
|
||||
canPlayType,
|
||||
'original canPlayType and patched canPlayType should not be equal'
|
||||
);
|
||||
|
||||
const patchedCanPlayType = video.canPlayType;
|
||||
const unpatchedCanPlayType = Html5.unpatchCanPlayType();
|
||||
|
||||
assert.strictEqual(
|
||||
canPlayType,
|
||||
Html5.TEST_VID.constructor.prototype.canPlayType,
|
||||
'original canPlayType and unpatched canPlayType should be equal'
|
||||
);
|
||||
assert.strictEqual(
|
||||
patchedCanPlayType,
|
||||
unpatchedCanPlayType,
|
||||
'patched canPlayType and function returned from unpatch are equal'
|
||||
);
|
||||
|
||||
browser.stub_ANDROID_VERSION(oldAV);
|
||||
browser.stub_IS_FIREFOX(oldIsFirefox);
|
||||
browser.stub_IS_CHROME(oldIsChrome);
|
||||
Html5.unpatchCanPlayType();
|
||||
});
|
||||
|
||||
QUnit.test('patchCanPlayType doesn\'t patch canplaytype with our function in Chrome for Android', function(assert) {
|
||||
// the patch runs automatically so we need to first unpatch
|
||||
Html5.unpatchCanPlayType();
|
||||
|
||||
const oldAV = browser.ANDROID_VERSION;
|
||||
const oldIsChrome = browser.IS_CHROME;
|
||||
const oldIsFirefox = browser.IS_FIREFOX;
|
||||
const video = document.createElement('video');
|
||||
const canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
|
||||
browser.stub_ANDROID_VERSION(4.0);
|
||||
browser.stub_IS_CHROME(true);
|
||||
browser.stub_IS_FIREFOX(false);
|
||||
Html5.patchCanPlayType();
|
||||
|
||||
assert.strictEqual(
|
||||
video.canPlayType,
|
||||
canPlayType,
|
||||
'original canPlayType and patched canPlayType should be equal'
|
||||
);
|
||||
|
||||
browser.stub_ANDROID_VERSION(oldAV);
|
||||
browser.stub_IS_CHROME(oldIsChrome);
|
||||
browser.stub_IS_FIREFOX(oldIsFirefox);
|
||||
Html5.unpatchCanPlayType();
|
||||
});
|
||||
|
||||
QUnit.test('patchCanPlayType doesn\'t patch canplaytype with our function in Firefox for Android', function(assert) {
|
||||
// the patch runs automatically so we need to first unpatch
|
||||
Html5.unpatchCanPlayType();
|
||||
|
||||
const oldAV = browser.ANDROID_VERSION;
|
||||
const oldIsFirefox = browser.IS_FIREFOX;
|
||||
const oldIsChrome = browser.IS_CHROME;
|
||||
const video = document.createElement('video');
|
||||
const canPlayType = Html5.TEST_VID.constructor.prototype.canPlayType;
|
||||
|
||||
browser.stub_ANDROID_VERSION(4.0);
|
||||
browser.stub_IS_FIREFOX(true);
|
||||
browser.stub_IS_CHROME(false);
|
||||
Html5.patchCanPlayType();
|
||||
|
||||
assert.strictEqual(
|
||||
video.canPlayType,
|
||||
canPlayType,
|
||||
'original canPlayType and patched canPlayType should be equal'
|
||||
);
|
||||
|
||||
browser.stub_ANDROID_VERSION(oldAV);
|
||||
browser.stub_IS_FIREFOX(oldIsFirefox);
|
||||
browser.stub_IS_CHROME(oldIsChrome);
|
||||
Html5.unpatchCanPlayType();
|
||||
});
|
||||
|
||||
QUnit.test('should return maybe for HLS urls on Android 4.0 or above when not Chrome or Firefox', function(assert) {
|
||||
const oldAV = browser.ANDROID_VERSION;
|
||||
const oldIsFirefox = browser.IS_FIREFOX;
|
||||
const oldIsChrome = browser.IS_CHROME;
|
||||
const video = document.createElement('video');
|
||||
|
||||
browser.stub_ANDROID_VERSION(4.0);
|
||||
browser.stub_IS_FIREFOX(false);
|
||||
browser.stub_IS_CHROME(false);
|
||||
Html5.patchCanPlayType();
|
||||
|
||||
assert.strictEqual(
|
||||
video.canPlayType('application/x-mpegurl'),
|
||||
'maybe',
|
||||
'android version 4.0 or above should be a maybe for x-mpegurl'
|
||||
);
|
||||
assert.strictEqual(
|
||||
video.canPlayType('application/x-mpegURL'),
|
||||
'maybe',
|
||||
'android version 4.0 or above should be a maybe for x-mpegURL'
|
||||
);
|
||||
assert.strictEqual(
|
||||
video.canPlayType('application/vnd.apple.mpegurl'),
|
||||
'maybe',
|
||||
'android version 4.0 or above should be a ' +
|
||||
'maybe for vnd.apple.mpegurl'
|
||||
);
|
||||
assert.strictEqual(
|
||||
video.canPlayType('application/vnd.apple.mpegURL'),
|
||||
'maybe',
|
||||
'android version 4.0 or above should be a ' +
|
||||
'maybe for vnd.apple.mpegurl'
|
||||
);
|
||||
|
||||
browser.stub_ANDROID_VERSION(oldAV);
|
||||
browser.stub_IS_FIREFOX(oldIsFirefox);
|
||||
browser.stub_IS_CHROME(oldIsChrome);
|
||||
Html5.unpatchCanPlayType();
|
||||
});
|
||||
|
||||
QUnit.test('error events may not set the errors property', function(assert) {
|
||||
assert.equal(tech.error(), undefined, 'no tech-level error');
|
||||
tech.trigger('error');
|
||||
|
Loading…
Reference in New Issue
Block a user