@tidal-music/player
Version:
Player logic for TIDAL
2,100 lines • 79.8 kB
JavaScript
const U = {
BTS: "application/vnd.tidal.bts",
DASH: "application/dash+xml",
EMU: "application/vnd.tidal.emu",
HLS: "application/vnd.apple.mpegurl"
}, se = "https://et.tidal.com/api/events", Oe = "https://et.tidal.com/api/public/events";
let z = Object.freeze({
apiUrl: "https://api.tidal.com/v1",
appVersion: "TIDAL Player",
clientPlatform: "web",
desiredVolumeLevel: 1,
eventUrl: se,
gatherEvents: !0,
loudnessNormalizationMode: "ALBUM",
outputDevicesEnabled: !1,
streamingWifiAudioQuality: "LOW"
});
function y(t) {
return z[t];
}
function M(t) {
return z = Object.freeze({
...z,
...t
}), Object.keys(t).forEach((e) => {
const r = e;
_e.dispatchEvent(new CustomEvent(r, { detail: t[r] }));
}), z;
}
const _e = new EventTarget();
var ne = (t) => {
throw TypeError(t);
}, ie = (t, e, r) => e.has(t) || ne("Cannot " + r), k = (t, e, r) => (ie(t, e, "read from private field"), r ? r.call(t) : e.get(t)), W = (t, e, r) => e.has(t) ? ne("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, r), F = (t, e, r, s) => (ie(t, e, "write to private field"), e.set(t, r), r), I, x, D, H;
class Ne {
constructor(e) {
W(this, I), W(this, x, !1), W(this, D), W(this, H), F(this, H, new URL(e)), this.synchronize();
}
/**
* Returns the current time adjusted to server-time.
*
* @param clientCurrentTime The current time on the client side. Defaults to Date.now().
* @returns The current adjusted time (or the client time if not synced yet).
*/
// eslint-disable-next-line no-restricted-syntax
now(e = Date.now()) {
return !k(this, D) || !k(this, I) ? (console.warn("TrueTime is not yet synchronized"), e) : k(this, D) + (e - k(this, I));
}
/**
* Synchronizes the client's time with the server's time.
* If the client's time is already synchronized within an hour, this method does nothing.
*
* @returns {Promise<void>} A promise that resolves when the synchronization is complete.
*/
async synchronize() {
if (!(k(this, I) && // eslint-disable-next-line no-restricted-syntax
Math.abs(Date.now() - k(this, I)) < 36e5 || k(this, x))) {
F(this, x, !0);
try {
const e = await fetch(k(this, H));
e.ok && e.headers.has("date") && (F(this, D, new Date(e.headers.get("date")).getTime()), F(this, I, Date.now()));
} catch (e) {
console.error(e);
}
F(this, x, !1);
}
}
/**
* Returns the timestamp of a performance mark with the specified name and detail.
* PS: `performance.mark` must be called with `startTime: trueTime.now()`.
*
* @param markName - The name of the performance mark.
* @param detail - Optional. The detail of the performance mark.
* @returns The timestamp of the performance mark, or undefined if not found.
* @throws ReferenceError if the performance mark is not found.
*/
timestamp(e, r) {
let s;
if (r) {
if (s = performance.getEntriesByName(e).find((i) => "detail" in i && i.detail === r), !s)
throw new ReferenceError(
`There is no performance entry named "${e}" with detail "${r}"`
);
} else
s = performance.getEntriesByName(e).pop();
return s ? s.startTime : void 0;
}
}
I = /* @__PURE__ */ new WeakMap(), x = /* @__PURE__ */ new WeakMap(), D = /* @__PURE__ */ new WeakMap(), H = /* @__PURE__ */ new WeakMap();
const g = new Ne("https://api.tidal.com/v1/ping"), Be = (t, e, r) => {
for (const s of t) {
const i = s.addedNodes[0];
s.type === "childList" && i.id === e && r();
}
};
function Ce() {
const t = document.getElementById("tidal-player-root");
if (!t)
return Promise.reject("No player root");
if ("video-one" in t.children)
return Promise.resolve();
const e = [];
return "video-one" in t.children || e.push(
new Promise((r) => {
new MutationObserver(
(s) => Be(s, "video-one", r)
).observe(t, { childList: !0 });
})
), Promise.all(e);
}
const O = document.createElement("video"), Le = (t) => {
t.setAttribute("crossorigin", "anonymous"), t.setAttribute("playsinline", "playsinline");
};
Le(O);
O.id = "video-one";
const Q = "tidal-player-root";
function Fe() {
let t = document.getElementById(Q);
if (!t) {
const e = document.createElement("template");
e.id = Q, document.body.appendChild(e), t = document.getElementById(Q);
}
return Re();
}
function Re() {
const t = document.getElementById(
Q
);
return t && (O.id in t.children || t.appendChild(O)), Ce();
}
function xe() {
return new Promise(
(t) => document.addEventListener(
"click",
() => {
O.readyState === HTMLMediaElement.HAVE_NOTHING && !O.src && O.load(), t();
},
{ once: !0 }
)
);
}
function De(t) {
return new Promise((e) => setTimeout(() => e(), t));
}
function Ue(t, e) {
return new Promise((r) => {
t.addEventListener(e, (s) => r(s), !1);
});
}
class We extends EventTarget {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - Setter
#t;
async dispatchAuthorized() {
const e = await this.#t.getCredentials();
e?.token ? this.dispatchEvent(
new CustomEvent("authorized", {
detail: {
credentials: e
}
})
) : this.dispatchEvent(
new CustomEvent("unauthenticated", { detail: { credentials: e } })
);
}
set credentialsProvider(e) {
this.#t = e, this.dispatchAuthorized().catch(console.error), this.#t.bus((r) => {
switch (r.detail.type) {
case "CredentialsUpdatedMessage":
this.dispatchAuthorized().catch(console.error);
break;
default:
console.warn("Unhandled event from credentials provider: ", r);
break;
}
});
}
get credentialsProvider() {
return this.#t;
}
}
class $ extends Error {
errorCode = null;
errorId = null;
referenceId;
constructor(e, r, s) {
super(`${e}: ${r} (${s})`), this.errorId = e, this.errorCode = r, this.referenceId = s;
}
toJSON() {
return {
errorCode: this.errorCode,
errorId: this.errorId,
referenceId: this.referenceId
};
}
toString() {
return JSON.stringify(this.toJSON());
}
}
async function B() {
if (S.credentialsProvider) {
const t = await S.credentialsProvider.getCredentials();
return !!(t.token && t.userId);
}
return await Ue(S, "authorized"), B();
}
const S = new We();
async function Ve() {
const t = await B(), e = async () => {
const { Pushkin: s } = await Promise.resolve().then(() => Bt);
return s.refresh();
}, r = async () => (await Promise.resolve().then(() => fe)).start();
if (t) {
M({
eventUrl: se,
gatherEvents: !0
});
try {
await Promise.all([e(), r()]);
} catch (s) {
console.error(s);
}
} else
M({
gatherEvents: !1
});
}
async function ze() {
const t = async () => (await Promise.resolve().then(() => fe)).start();
M({
eventUrl: Oe,
gatherEvents: !0
});
try {
await t();
} catch (e) {
console.error(e);
}
}
S.addEventListener("authorized", () => {
Ve().then().catch(console.error);
});
S.addEventListener("unauthenticated", () => {
ze().then().catch(console.error);
});
async function ee() {
return S.credentialsProvider ? (await S.credentialsProvider.getCredentials()).token ?? null : null;
}
class He extends EventTarget {
dispatchError(e) {
this.dispatchEvent(
new CustomEvent("error", {
detail: e.toJSON()
})
);
}
}
const P = new He();
class Qe {
#t = /* @__PURE__ */ new Map();
#r = /* @__PURE__ */ new Map();
#s = /* @__PURE__ */ new Map();
#e = /* @__PURE__ */ new Map();
/**
* Clones a session to re-use the media product and playback content for a new session.
*
* @param from - streamingSessionId to clone
* @param to - target streamingSessionId
*/
clone(e, r) {
const s = this.getMediaProductTransition(e), i = this.getStreamInfo(e), a = this.getPlaybackInfo(e);
if (!s || !i || !a)
throw new Error(
`Cannot clone ${e}. Missing mediaProductTransition or streamInfo.`
);
this.saveMediaProductTransition(r, {
...s,
playbackContext: {
...s.playbackContext,
playbackSessionId: r
}
}), this.saveStreamInfo(r, {
...i,
streamingSessionId: r
}), this.savePlaybackInfo(r, {
...a,
streamingSessionId: r
});
}
deleteMediaProductTransition(e) {
this.#t.delete(e);
}
/**
* Removed cached playbackInfo, streamInfo and mediaProductTransition for session.
* For re-using playbackInfo etc for other sessions make sure to run clone before deletion!
*
* @see {@link StreamingSessionStore.clone}
*/
deleteSession(e) {
this.deleteMediaProductTransition(e), this.#r.delete(e), this.#s.delete(e), this.deleteStreamInfo(e);
}
deleteStartedStreamInfo(e) {
this.#s.delete(e);
}
deleteStreamInfo(e) {
this.#e.delete(e);
}
getMediaProductTransition(e) {
return e ? this.#t.get(e) : void 0;
}
getPlaybackInfo(e) {
return e ? this.#r.get(e) : void 0;
}
getStreamInfo(e) {
return e ? this.#e.get(e) : void 0;
}
hasMediaProductTransition(e) {
return this.#t.has(e);
}
hasPlaybackInfo(e) {
return this.#r.has(e);
}
hasStartedStreamInfo(e) {
return this.#s.has(e);
}
hasStreamInfo(e) {
return this.#e.has(e);
}
overwriteDuration(e, r) {
const s = this.#t.get(e);
s && (s.playbackContext = {
...s.playbackContext,
actualDuration: r
}, this.saveMediaProductTransition(e, s));
}
saveMediaProductTransition(e, r) {
this.#t.set(
e,
r
);
}
savePlaybackInfo(e, r) {
this.#r.set(e, r);
}
saveStreamInfo(e, r) {
this.#e.set(e, r);
}
setStartedStreamInfo(e) {
return this.#s.set(e, !0);
}
}
const E = new Qe();
class $e {
activePlayer;
preloadPlayer;
get preloadedMediaProduct() {
return E.getMediaProductTransition(
this.preloadedStreamingSessionId
)?.mediaProduct ?? void 0;
}
get preloadedStreamingSessionId() {
return this.preloadPlayer?.preloadedStreamingSessionId ?? void 0;
}
}
const l = new $e();
let K;
const Ge = [
{
itemTypes: ["track", "video", "demo"],
player: "shaka",
qualities: ["HIGH", "LOSSLESS", "LOW", "HI_RES_LOSSLESS"]
}
];
let C = Ge;
const w = {
browser: void 0,
native: void 0,
shaka: void 0
};
function je(t) {
C = t;
}
async function qe() {
await Promise.all(
C.map((t) => {
const e = w[t.player];
return e ? e.reset() : Promise.resolve();
})
), l.activePlayer = void 0, l.preloadPlayer = void 0;
}
function X(t) {
t.name !== "nativePlayer" && w.native && w.native.abandon(), l.activePlayer = t;
}
async function Ke(t) {
X(t), await Promise.all(
C.filter((e) => w[e.player] !== l.activePlayer).map(async (e) => {
const r = w[e.player];
return r && await r.reset(), Promise.resolve();
})
), await l.activePlayer?.skipToPreloadedMediaProduct(), await l.activePlayer?.play();
}
function ae() {
P.removeEventListener("ended", K);
}
function Je(t) {
l.activePlayer && t.name === l.activePlayer.name || (K = () => {
Ke(t).then().catch(console.error);
}, P.addEventListener("ended", K, { once: !0 }));
}
async function oe() {
const { default: t } = await import("./nativePlayer-CPyCegnV.js");
return w.native || (w.native = new t()), w.native;
}
async function Ye() {
const { default: t } = await import("./browserPlayer-CIpjt2eR.js");
return w.browser || (w.browser = new t()), w.browser;
}
async function Xe() {
const { default: t } = await import("./shakaPlayer-Bl5ADZ6B.js");
return w.shaka || (w.shaka = new t()), w.shaka;
}
async function ce(t, e) {
const r = C.filter((i) => i.itemTypes.includes(t)).filter(
(i) => t === "track" && i.qualities && e ? i.qualities.includes(e) : !0
);
r.length === 0 && console.error(
`No player found to handle audio quality "${String(
e
)}" for product type "${t}" in player config: `,
C
);
const { player: s } = r[0];
switch (s) {
case "browser":
return Ye();
case "native":
return oe();
case "shaka":
return Xe();
default:
throw new Error("No player found.");
}
}
async function Ze() {
await Promise.all(
C.map((t) => {
const e = w[t.player];
return e ? e.unloadPreloadedMediaProduct() : Promise.resolve();
})
);
}
function zt() {
return l.activePlayer?.getPosition() ?? 0;
}
function Ht() {
return y("loudnessNormalizationMode");
}
function Qt() {
return l.activePlayer?.currentMediaProduct ?? null;
}
function $t() {
return l.preloadedMediaProduct ?? null;
}
async function Gt() {
const { outputDevices: t } = await import("./output-devices-B2CSTw2l.js");
return [...t.outputDevices];
}
function jt() {
const t = l.activePlayer;
if (t) {
const e = E.getMediaProductTransition(
t.currentStreamingSessionId
);
if (e)
return e.playbackContext;
}
}
function qt() {
return l.activePlayer?.playbackState ?? "IDLE";
}
function Kt() {
return "0.7.0";
}
function Jt() {
return y("streamingWifiAudioQuality");
}
function Yt() {
return y("desiredVolumeLevel");
}
class et {
#t;
constructor() {
this.#t = /* @__PURE__ */ new Map();
}
async #r(e, r) {
const s = new TextEncoder().encode(
`${e}-${r}`
), i = await crypto.subtle.digest("SHA-1", s);
return Array.from(new Uint8Array(i)).map((d) => d.toString(16).padStart(2, "0")).join("");
}
/**
* Delete a logged event by name and streamingSessionId.
*/
async delete({
name: e,
streamingSessionId: r
}) {
const s = await this.#r(
r,
e
);
this.#t.delete(s);
}
/**
* Get a logged event by name and streamingSessionId.
*/
async get({
name: e,
streamingSessionId: r
}) {
const s = await this.#r(
r,
e
);
return this.#t.get(s);
}
/**
* Adds or updates an event.
*/
async put(e) {
const r = await this.#r(
e.streamingSessionId,
e.name
);
this.#t.set(r, e);
}
}
const J = new et();
async function L(t, e) {
return y("gatherEvents") ? async (r) => {
try {
const s = await J.get({
name: t,
streamingSessionId: r.streamingSessionId
}), i = Object.assign(
{},
e,
s ? s.payload : {},
r
);
for (const a of Object.keys(r)) {
const o = a;
Array.isArray(r[o]) && (i[o] = [
...e[o] || [],
...s && s.payload[o] || [],
...r[o] || []
]);
}
return await J.put({
name: t,
payload: i,
streamingSessionId: r.streamingSessionId
}), {
name: t,
payload: i,
streamingSessionId: r.streamingSessionId
};
} catch (s) {
console.error(s);
}
} : (r) => Promise.resolve(void 0);
}
const tt = {
endReason: "COMPLETE",
endTimestamp: 0,
errorCode: null,
errorMessage: null,
startTimestamp: 0,
streamingSessionId: ""
}, rt = await L(
"drm_license_fetch",
tt
);
function Xt(t) {
return rt(t);
}
const st = {
endReason: "COMPLETE",
endTimestamp: 0,
errorCode: null,
errorMessage: null,
startTimestamp: 0,
streamingSessionId: ""
}, nt = await L(
"playback_info_fetch",
st
);
function G(t) {
return nt(t);
}
function Zt(t) {
switch (t) {
case "bluetooth":
return "BLUETOOTH";
case "builtIn":
return "BUILT_IN";
case "displayPort":
return "DISPLAY_PORT";
case "hdmi":
return "HDMI";
case "systemDefault":
return "SYSTEM_DEFAULT";
case "usb":
return "USB";
// Never happens (cannot be chose by user)
case "airplay":
case "windowsCommunication":
default:
return;
}
}
const it = {
actualAssetPresentation: "FULL",
actualAudioMode: "STEREO",
actualProductId: null,
actualQuality: "LOSSLESS",
actualStartTimestamp: 0,
actualStreamType: "ON_DEMAND",
adaptations: [],
cdm: "WIDEVINE",
cdmVersion: null,
endReason: "COMPLETE",
endTimestamp: 0,
errorCode: null,
errorMessage: null,
hasAds: !1,
idealStartTimestamp: 0,
outputDevice: null,
productType: "TRACK",
stalls: [],
streamingSessionId: ""
}, at = await L(
"playback_statistics",
it
);
function te(t) {
return at(t);
}
const ot = {
streamingSessionId: "",
timestamp: 0
}, ct = await L(
"streaming_session_end",
ot
);
function dt(t) {
return ct(t);
}
const lt = {
"Amazon Silk": "amazon_silk",
"Android Browser": "android",
Bada: "bada",
BlackBerry: "blackberry",
Chrome: "chrome",
Chromium: "chromium",
Electron: "electron",
Epiphany: "epiphany",
Firefox: "firefox",
Focus: "focus",
Generic: "generic",
"Google Search": "google_search",
Googlebot: "googlebot",
"Internet Explorer": "ie",
"K-Meleon": "k_meleon",
Maxthon: "maxthon",
"Microsoft Edge": "edge",
"MZ Browser": "mz",
"NAVER Whale Browser": "naver",
Opera: "opera",
"Opera Coast": "opera_coast",
PhantomJS: "phantomjs",
Puffin: "puffin",
QupZilla: "qupzilla",
QQ: "qq",
QQLite: "qqlite",
Safari: "safari",
Sailfish: "sailfish",
"Samsung Internet for Android": "samsung_internet",
SeaMonkey: "seamonkey",
Sleipnir: "sleipnir",
Swing: "swing",
Tizen: "tizen",
"UC Browser": "uc",
Vivaldi: "vivaldi",
"WebOS Browser": "webos",
WeChat: "wechat",
"Yandex Browser": "yandex",
Roku: "roku"
}, de = {
amazon_silk: "Amazon Silk",
android: "Android Browser",
bada: "Bada",
blackberry: "BlackBerry",
chrome: "Chrome",
chromium: "Chromium",
electron: "Electron",
epiphany: "Epiphany",
firefox: "Firefox",
focus: "Focus",
generic: "Generic",
googlebot: "Googlebot",
google_search: "Google Search",
ie: "Internet Explorer",
k_meleon: "K-Meleon",
maxthon: "Maxthon",
edge: "Microsoft Edge",
mz: "MZ Browser",
naver: "NAVER Whale Browser",
opera: "Opera",
opera_coast: "Opera Coast",
phantomjs: "PhantomJS",
puffin: "Puffin",
qupzilla: "QupZilla",
qq: "QQ Browser",
qqlite: "QQ Browser Lite",
safari: "Safari",
sailfish: "Sailfish",
samsung_internet: "Samsung Internet for Android",
seamonkey: "SeaMonkey",
sleipnir: "Sleipnir",
swing: "Swing",
tizen: "Tizen",
uc: "UC Browser",
vivaldi: "Vivaldi",
webos: "WebOS Browser",
wechat: "WeChat",
yandex: "Yandex Browser"
}, m = {
tablet: "tablet",
mobile: "mobile",
desktop: "desktop",
tv: "tv"
}, v = {
WindowsPhone: "Windows Phone",
Windows: "Windows",
MacOS: "macOS",
iOS: "iOS",
Android: "Android",
WebOS: "WebOS",
BlackBerry: "BlackBerry",
Bada: "Bada",
Tizen: "Tizen",
Linux: "Linux",
ChromeOS: "Chrome OS",
PlayStation4: "PlayStation 4",
Roku: "Roku"
}, T = {
EdgeHTML: "EdgeHTML",
Blink: "Blink",
Trident: "Trident",
Presto: "Presto",
Gecko: "Gecko",
WebKit: "WebKit"
};
class n {
/**
* Get first matched item for a string
* @param {RegExp} regexp
* @param {String} ua
* @return {Array|{index: number, input: string}|*|boolean|string}
*/
static getFirstMatch(e, r) {
const s = r.match(e);
return s && s.length > 0 && s[1] || "";
}
/**
* Get second matched item for a string
* @param regexp
* @param {String} ua
* @return {Array|{index: number, input: string}|*|boolean|string}
*/
static getSecondMatch(e, r) {
const s = r.match(e);
return s && s.length > 1 && s[2] || "";
}
/**
* Match a regexp and return a constant or undefined
* @param {RegExp} regexp
* @param {String} ua
* @param {*} _const Any const that will be returned if regexp matches the string
* @return {*}
*/
static matchAndReturnConst(e, r, s) {
if (e.test(r))
return s;
}
static getWindowsVersionName(e) {
switch (e) {
case "NT":
return "NT";
case "XP":
return "XP";
case "NT 5.0":
return "2000";
case "NT 5.1":
return "XP";
case "NT 5.2":
return "2003";
case "NT 6.0":
return "Vista";
case "NT 6.1":
return "7";
case "NT 6.2":
return "8";
case "NT 6.3":
return "8.1";
case "NT 10.0":
return "10";
default:
return;
}
}
/**
* Get macOS version name
* 10.5 - Leopard
* 10.6 - Snow Leopard
* 10.7 - Lion
* 10.8 - Mountain Lion
* 10.9 - Mavericks
* 10.10 - Yosemite
* 10.11 - El Capitan
* 10.12 - Sierra
* 10.13 - High Sierra
* 10.14 - Mojave
* 10.15 - Catalina
*
* @example
* getMacOSVersionName("10.14") // 'Mojave'
*
* @param {string} version
* @return {string} versionName
*/
static getMacOSVersionName(e) {
const r = e.split(".").splice(0, 2).map((s) => parseInt(s, 10) || 0);
if (r.push(0), r[0] === 10)
switch (r[1]) {
case 5:
return "Leopard";
case 6:
return "Snow Leopard";
case 7:
return "Lion";
case 8:
return "Mountain Lion";
case 9:
return "Mavericks";
case 10:
return "Yosemite";
case 11:
return "El Capitan";
case 12:
return "Sierra";
case 13:
return "High Sierra";
case 14:
return "Mojave";
case 15:
return "Catalina";
default:
return;
}
}
/**
* Get Android version name
* 1.5 - Cupcake
* 1.6 - Donut
* 2.0 - Eclair
* 2.1 - Eclair
* 2.2 - Froyo
* 2.x - Gingerbread
* 3.x - Honeycomb
* 4.0 - Ice Cream Sandwich
* 4.1 - Jelly Bean
* 4.4 - KitKat
* 5.x - Lollipop
* 6.x - Marshmallow
* 7.x - Nougat
* 8.x - Oreo
* 9.x - Pie
*
* @example
* getAndroidVersionName("7.0") // 'Nougat'
*
* @param {string} version
* @return {string} versionName
*/
static getAndroidVersionName(e) {
const r = e.split(".").splice(0, 2).map((s) => parseInt(s, 10) || 0);
if (r.push(0), !(r[0] === 1 && r[1] < 5)) {
if (r[0] === 1 && r[1] < 6) return "Cupcake";
if (r[0] === 1 && r[1] >= 6) return "Donut";
if (r[0] === 2 && r[1] < 2) return "Eclair";
if (r[0] === 2 && r[1] === 2) return "Froyo";
if (r[0] === 2 && r[1] > 2) return "Gingerbread";
if (r[0] === 3) return "Honeycomb";
if (r[0] === 4 && r[1] < 1) return "Ice Cream Sandwich";
if (r[0] === 4 && r[1] < 4) return "Jelly Bean";
if (r[0] === 4 && r[1] >= 4) return "KitKat";
if (r[0] === 5) return "Lollipop";
if (r[0] === 6) return "Marshmallow";
if (r[0] === 7) return "Nougat";
if (r[0] === 8) return "Oreo";
if (r[0] === 9) return "Pie";
}
}
/**
* Get version precisions count
*
* @example
* getVersionPrecision("1.10.3") // 3
*
* @param {string} version
* @return {number}
*/
static getVersionPrecision(e) {
return e.split(".").length;
}
/**
* Calculate browser version weight
*
* @example
* compareVersions('1.10.2.1', '1.8.2.1.90') // 1
* compareVersions('1.010.2.1', '1.09.2.1.90'); // 1
* compareVersions('1.10.2.1', '1.10.2.1'); // 0
* compareVersions('1.10.2.1', '1.0800.2'); // -1
* compareVersions('1.10.2.1', '1.10', true); // 0
*
* @param {String} versionA versions versions to compare
* @param {String} versionB versions versions to compare
* @param {boolean} [isLoose] enable loose comparison
* @return {Number} comparison result: -1 when versionA is lower,
* 1 when versionA is bigger, 0 when both equal
*/
/* eslint consistent-return: 1 */
static compareVersions(e, r, s = !1) {
const i = n.getVersionPrecision(e), a = n.getVersionPrecision(r);
let o = Math.max(i, a), d = 0;
const c = n.map([e, r], (h) => {
const f = o - n.getVersionPrecision(h), b = h + new Array(f + 1).join(".0");
return n.map(b.split("."), (p) => new Array(20 - p.length).join("0") + p).reverse();
});
for (s && (d = o - Math.min(i, a)), o -= 1; o >= d; ) {
if (c[0][o] > c[1][o])
return 1;
if (c[0][o] === c[1][o]) {
if (o === d)
return 0;
o -= 1;
} else if (c[0][o] < c[1][o])
return -1;
}
}
/**
* Array::map polyfill
*
* @param {Array} arr
* @param {Function} iterator
* @return {Array}
*/
static map(e, r) {
const s = [];
let i;
if (Array.prototype.map)
return Array.prototype.map.call(e, r);
for (i = 0; i < e.length; i += 1)
s.push(r(e[i]));
return s;
}
/**
* Array::find polyfill
*
* @param {Array} arr
* @param {Function} predicate
* @return {Array}
*/
static find(e, r) {
let s, i;
if (Array.prototype.find)
return Array.prototype.find.call(e, r);
for (s = 0, i = e.length; s < i; s += 1) {
const a = e[s];
if (r(a, s))
return a;
}
}
/**
* Object::assign polyfill
*
* @param {Object} obj
* @param {Object} ...objs
* @return {Object}
*/
static assign(e, ...r) {
const s = e;
let i, a;
if (Object.assign)
return Object.assign(e, ...r);
for (i = 0, a = r.length; i < a; i += 1) {
const o = r[i];
typeof o == "object" && o !== null && Object.keys(o).forEach((c) => {
s[c] = o[c];
});
}
return e;
}
/**
* Get short version/alias for a browser name
*
* @example
* getBrowserAlias('Microsoft Edge') // edge
*
* @param {string} browserName
* @return {string}
*/
static getBrowserAlias(e) {
return lt[e];
}
/**
* Get short version/alias for a browser name
*
* @example
* getBrowserAlias('edge') // Microsoft Edge
*
* @param {string} browserAlias
* @return {string}
*/
static getBrowserTypeByAlias(e) {
return de[e] || "";
}
}
const u = /version\/(\d+(\.?_?\d+)+)/i, ut = [
/* Googlebot */
{
test: [/googlebot/i],
describe(t) {
const e = {
name: "Googlebot"
}, r = n.getFirstMatch(/googlebot\/(\d+(\.\d+))/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
/* Opera < 13.0 */
{
test: [/opera/i],
describe(t) {
const e = {
name: "Opera"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
/* Opera > 13.0 */
{
test: [/opr\/|opios/i],
describe(t) {
const e = {
name: "Opera"
}, r = n.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/SamsungBrowser/i],
describe(t) {
const e = {
name: "Samsung Internet for Android"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/Whale/i],
describe(t) {
const e = {
name: "NAVER Whale Browser"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/MZBrowser/i],
describe(t) {
const e = {
name: "MZ Browser"
}, r = n.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/focus/i],
describe(t) {
const e = {
name: "Focus"
}, r = n.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/swing/i],
describe(t) {
const e = {
name: "Swing"
}, r = n.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/coast/i],
describe(t) {
const e = {
name: "Opera Coast"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/opt\/\d+(?:.?_?\d+)+/i],
describe(t) {
const e = {
name: "Opera Touch"
}, r = n.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/yabrowser/i],
describe(t) {
const e = {
name: "Yandex Browser"
}, r = n.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/ucbrowser/i],
describe(t) {
const e = {
name: "UC Browser"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/Maxthon|mxios/i],
describe(t) {
const e = {
name: "Maxthon"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/epiphany/i],
describe(t) {
const e = {
name: "Epiphany"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/puffin/i],
describe(t) {
const e = {
name: "Puffin"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/sleipnir/i],
describe(t) {
const e = {
name: "Sleipnir"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/k-meleon/i],
describe(t) {
const e = {
name: "K-Meleon"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/micromessenger/i],
describe(t) {
const e = {
name: "WeChat"
}, r = n.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/qqbrowser/i],
describe(t) {
const e = {
name: /qqbrowserlite/i.test(t) ? "QQ Browser Lite" : "QQ Browser"
}, r = n.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/msie|trident/i],
describe(t) {
const e = {
name: "Internet Explorer"
}, r = n.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/\sedg\//i],
describe(t) {
const e = {
name: "Microsoft Edge"
}, r = n.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/edg([ea]|ios)/i],
describe(t) {
const e = {
name: "Microsoft Edge"
}, r = n.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/vivaldi/i],
describe(t) {
const e = {
name: "Vivaldi"
}, r = n.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/seamonkey/i],
describe(t) {
const e = {
name: "SeaMonkey"
}, r = n.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/sailfish/i],
describe(t) {
const e = {
name: "Sailfish"
}, r = n.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/silk/i],
describe(t) {
const e = {
name: "Amazon Silk"
}, r = n.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/phantom/i],
describe(t) {
const e = {
name: "PhantomJS"
}, r = n.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/slimerjs/i],
describe(t) {
const e = {
name: "SlimerJS"
}, r = n.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/blackberry|\bbb\d+/i, /rim\stablet/i],
describe(t) {
const e = {
name: "BlackBerry"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/(web|hpw)[o0]s/i],
describe(t) {
const e = {
name: "WebOS Browser"
}, r = n.getFirstMatch(u, t) || n.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/bada/i],
describe(t) {
const e = {
name: "Bada"
}, r = n.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/tizen/i],
describe(t) {
const e = {
name: "Tizen"
}, r = n.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/qupzilla/i],
describe(t) {
const e = {
name: "QupZilla"
}, r = n.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/firefox|iceweasel|fxios/i],
describe(t) {
const e = {
name: "Firefox"
}, r = n.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/electron/i],
describe(t) {
const e = {
name: "Electron"
}, r = n.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/MiuiBrowser/i],
describe(t) {
const e = {
name: "Miui"
}, r = n.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/chromium/i],
describe(t) {
const e = {
name: "Chromium"
}, r = n.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i, t) || n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
{
test: [/chrome|crios|crmo/i],
describe(t) {
const e = {
name: "Chrome"
}, r = n.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
{
test: [/GSA/i],
describe(t) {
const e = {
name: "Google Search"
}, r = n.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
/* Android Browser */
{
test(t) {
const e = !t.test(/like android/i), r = t.test(/android/i);
return e && r;
},
describe(t) {
const e = {
name: "Android Browser"
}, r = n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
/* PlayStation 4 */
{
test: [/playstation 4/i],
describe(t) {
const e = {
name: "PlayStation 4"
}, r = n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
/* Safari */
{
test: [/safari|applewebkit/i],
describe(t) {
const e = {
name: "Safari"
}, r = n.getFirstMatch(u, t);
return r && (e.version = r), e;
}
},
/* Something else */
{
test: [/.*/i],
describe(t) {
const e = /^(.*)\/(.*) /, r = /^(.*)\/(.*)[ \t]\((.*)/, i = t.search("\\(") !== -1 ? r : e;
return {
name: n.getFirstMatch(i, t),
version: n.getSecondMatch(i, t)
};
}
}
], ht = [
/* Roku */
{
test: [/Roku\/DVP/],
describe(t) {
const e = n.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i, t);
return {
name: v.Roku,
version: e
};
}
},
/* Windows Phone */
{
test: [/windows phone/i],
describe(t) {
const e = n.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i, t);
return {
name: v.WindowsPhone,
version: e
};
}
},
/* Windows */
{
test: [/windows /i],
describe(t) {
const e = n.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i, t), r = n.getWindowsVersionName(e);
return {
name: v.Windows,
version: e,
versionName: r
};
}
},
/* Firefox on iPad */
{
test: [/Macintosh(.*?) FxiOS(.*?)\//],
describe(t) {
const e = {
name: v.iOS
}, r = n.getSecondMatch(/(Version\/)(\d[\d.]+)/, t);
return r && (e.version = r), e;
}
},
/* macOS */
{
test: [/macintosh/i],
describe(t) {
const e = n.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i, t).replace(/[_\s]/g, "."), r = n.getMacOSVersionName(e), s = {
name: v.MacOS,
version: e
};
return r && (s.versionName = r), s;
}
},
/* iOS */
{
test: [/(ipod|iphone|ipad)/i],
describe(t) {
const e = n.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i, t).replace(/[_\s]/g, ".");
return {
name: v.iOS,
version: e
};
}
},
/* Android */
{
test(t) {
const e = !t.test(/like android/i), r = t.test(/android/i);
return e && r;
},
describe(t) {
const e = n.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i, t), r = n.getAndroidVersionName(e), s = {
name: v.Android,
version: e
};
return r && (s.versionName = r), s;
}
},
/* WebOS */
{
test: [/(web|hpw)[o0]s/i],
describe(t) {
const e = n.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i, t), r = {
name: v.WebOS
};
return e && e.length && (r.version = e), r;
}
},
/* BlackBerry */
{
test: [/blackberry|\bbb\d+/i, /rim\stablet/i],
describe(t) {
const e = n.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i, t) || n.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i, t) || n.getFirstMatch(/\bbb(\d+)/i, t);
return {
name: v.BlackBerry,
version: e
};
}
},
/* Bada */
{
test: [/bada/i],
describe(t) {
const e = n.getFirstMatch(/bada\/(\d+(\.\d+)*)/i, t);
return {
name: v.Bada,
version: e
};
}
},
/* Tizen */
{
test: [/tizen/i],
describe(t) {
const e = n.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i, t);
return {
name: v.Tizen,
version: e
};
}
},
/* Linux */
{
test: [/linux/i],
describe() {
return {
name: v.Linux
};
}
},
/* Chrome OS */
{
test: [/CrOS/],
describe() {
return {
name: v.ChromeOS
};
}
},
/* Playstation 4 */
{
test: [/PlayStation 4/],
describe(t) {
const e = n.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i, t);
return {
name: v.PlayStation4,
version: e
};
}
}
], mt = [
/* Googlebot */
{
test: [/googlebot/i],
describe() {
return {
type: "bot",
vendor: "Google"
};
}
},
/* Huawei */
{
test: [/huawei/i],
describe(t) {
const e = n.getFirstMatch(/(can-l01)/i, t) && "Nova", r = {
type: m.mobile,
vendor: "Huawei"
};
return e && (r.model = e), r;
}
},
/* Nexus Tablet */
{
test: [/nexus\s*(?:7|8|9|10).*/i],
describe() {
return {
type: m.tablet,
vendor: "Nexus"
};
}
},
/* iPad */
{
test: [/ipad/i],
describe() {
return {
type: m.tablet,
vendor: "Apple",
model: "iPad"
};
}
},
/* Firefox on iPad */
{
test: [/Macintosh(.*?) FxiOS(.*?)\//],
describe() {
return {
type: m.tablet,
vendor: "Apple",
model: "iPad"
};
}
},
/* Amazon Kindle Fire */
{
test: [/kftt build/i],
describe() {
return {
type: m.tablet,
vendor: "Amazon",
model: "Kindle Fire HD 7"
};
}
},
/* Another Amazon Tablet with Silk */
{
test: [/silk/i],
describe() {
return {
type: m.tablet,
vendor: "Amazon"
};
}
},
/* Tablet */
{
test: [/tablet(?! pc)/i],
describe() {
return {
type: m.tablet
};
}
},
/* iPod/iPhone */
{
test(t) {
const e = t.test(/ipod|iphone/i), r = t.test(/like (ipod|iphone)/i);
return e && !r;
},
describe(t) {
const e = n.getFirstMatch(/(ipod|iphone)/i, t);
return {
type: m.mobile,
vendor: "Apple",
model: e
};
}
},
/* Nexus Mobile */
{
test: [/nexus\s*[0-6].*/i, /galaxy nexus/i],
describe() {
return {
type: m.mobile,
vendor: "Nexus"
};
}
},
/* Mobile */
{
test: [/[^-]mobi/i],
describe() {
return {
type: m.mobile
};
}
},
/* BlackBerry */
{
test(t) {
return t.getBrowserName(!0) === "blackberry";
},
describe() {
return {
type: m.mobile,
vendor: "BlackBerry"
};
}
},
/* Bada */
{
test(t) {
return t.getBrowserName(!0) === "bada";
},
describe() {
return {
type: m.mobile
};
}
},
/* Windows Phone */
{
test(t) {
return t.getBrowserName() === "windows phone";
},
describe() {
return {
type: m.mobile,
vendor: "Microsoft"
};
}
},
/* Android Tablet */
{
test(t) {
const e = Number(String(t.getOSVersion()).split(".")[0]);
return t.getOSName(!0) === "android" && e >= 3;
},
describe() {
return {
type: m.tablet
};
}
},
/* Android Mobile */
{
test(t) {
return t.getOSName(!0) === "android";
},
describe() {
return {
type: m.mobile
};
}
},
/* desktop */
{
test(t) {
return t.getOSName(!0) === "macos";
},
describe() {
return {
type: m.desktop,
vendor: "Apple"
};
}
},
/* Windows */
{
test(t) {
return t.getOSName(!0) === "windows";
},
describe() {
return {
type: m.desktop
};
}
},
/* Linux */
{
test(t) {
return t.getOSName(!0) === "linux";
},
describe() {
return {
type: m.desktop
};
}
},
/* PlayStation 4 */
{
test(t) {
return t.getOSName(!0) === "playstation 4";
},
describe() {
return {
type: m.tv
};
}
},
/* Roku */
{
test(t) {
return t.getOSName(!0) === "roku";
},
describe() {
return {
type: m.tv
};
}
}
], ft = [
/* EdgeHTML */
{
test(t) {
return t.getBrowserName(!0) === "microsoft edge";
},
describe(t) {
if (/\sedg\//i.test(t))
return {
name: T.Blink
};
const r = n.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i, t);
return {
name: T.EdgeHTML,
version: r
};
}
},
/* Trident */
{
test: [/trident/i],
describe(t) {
const e = {
name: T.Trident
}, r = n.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
/* Presto */
{
test(t) {
return t.test(/presto/i);
},
describe(t) {
const e = {
name: T.Presto
}, r = n.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
/* Gecko */
{
test(t) {
const e = t.test(/gecko/i), r = t.test(/like gecko/i);
return e && !r;
},
describe(t) {
const e = {
name: T.Gecko
}, r = n.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
},
/* Blink */
{
test: [/(apple)?webkit\/537\.36/i],
describe() {
return {
name: T.Blink
};
}
},
/* WebKit */
{
test: [/(apple)?webkit/i],
describe(t) {
const e = {
name: T.WebKit
}, r = n.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i, t);
return r && (e.version = r), e;
}
}
];
class re {
/**
* Create instance of Parser
*
* @param {String} UA User-Agent string
* @param {Boolean} [skipParsing=false] parser can skip parsing in purpose of performance
* improvements if you need to make a more particular parsing
* like {@link Parser#parseBrowser} or {@link Parser#parsePlatform}
*
* @throw {Error} in case of empty UA String
*
* @constructor
*/
constructor(e, r = !1) {
if (e == null || e === "")
throw new Error("UserAgent parameter can't be empty");
this._ua = e, this.parsedResult = {}, r !== !0 && this.parse();
}
/**
* Get UserAgent string of current Parser instance
* @return {String} User-Agent String of the current <Parser> object
*
* @public
*/
getUA() {
return this._ua;
}
/**
* Test a UA string for a regexp
* @param {RegExp} regex
* @return {Boolean}
*/
test(e) {
return e.test(this._ua);
}
/**
* Get parsed browser object
* @return {Object}
*/
parseBrowser() {
this.parsedResult.browser = {};
const e = n.find(ut, (r) => {
if (typeof r.test == "function")
return r.test(this);
if (r.test instanceof Array)
return r.test.some((s) => this.test(s));
throw new Error("Browser's test function is not valid");
});
return e && (this.parsedResult.browser = e.describe(this.getUA())), this.parsedResult.browser;
}
/**
* Get parsed browser object
* @return {Object}
*
* @public
*/
getBrowser() {
return this.parsedResult.browser ? this.parsedResult.browser : this.parseBrowser();
}
/**
* Get browser's name
* @return {String} Browser's name or an empty string
*
* @public
*/
getBrowserName(e) {
return e ? String(this.getBrowser().name).toLowerCase() || "" : this.getBrowser().name || "";
}
/**
* Get browser's version
* @return {String} version of browser
*
* @public
*/
getBrowserVersion() {
return this.getBrowser().version;
}
/**
* Get OS
* @return {Object}
*
* @example
* this.getOS();
* {
* name: 'macOS',
* version: '10.11.12'
* }
*/
getOS() {
return this.parsedResult.os ? this.parsedResult.os : this.parseOS();
}
/**
* Parse OS and save it to this.parsedResult.os
* @return {*|{}}
*/
parseOS() {
this.parsedResult.os = {};
const e = n.find(ht, (r) => {
if (typeof r.test == "function")
return r.test(this);
if (r.test instanceof Array)
return r.test.some((s) => this.test(s));
throw new Error("Browser's test function is not valid");
});
return e && (this.parsedResult.os = e.describe(this.getUA())), this.parsedResult.os;
}
/**
* Get OS name
* @param {Boolean} [toLowerCase] return lower-cased value
* @return {String} name of the OS — macOS, Windows, Linux, etc.
*/
getOSName(e) {
const { name: r } = this.getOS();
return e ? String(r).toLowerCase() || "" : r || "";
}
/**
* Get OS version
* @return {String} full version with dots ('10.11.12', '5.6', etc)
*/
getOSVersion() {
return this.getOS().version;
}
/**
* Get parsed platform
* @return {{}}
*/
getPlatform() {
return this.parsedResult.platform ? this.parsedResult.platform : this.parsePlatform();
}
/**
* Get platform name
* @param {Boolean} [toLowerCase=false]
* @return {*}
*/
getPlatformType(e = !1) {
const { type: r } = this.getPlatform();
return e ? String(r).toLowerCase() || "" : r || "";
}
/**
* Get parsed platform
* @return {{}}
*/
parsePlatform() {
this.parsedResult.platform = {};
const e = n.find(mt, (r) => {
if (typeof r.test == "function")
return r.test(this);
if (r.test instanceof Array)
return r.test.some((s) => this.test(s));
throw new Error("Browser's test function is not valid");
});
return e && (this.parsedResult.platform = e.describe(this.getUA())), this.parsedResult.platform;
}
/**
* Get parsed engine
* @return {{}}
*/
getEngine() {
return this.parsedResult.engine ? this.parsedResult.engine : this.parseEngine();
}
/**
* Get engines's name
* @return {String} Engines's name or an empty string
*
* @public
*/
getEngineName(e) {
return e ? String(this.getEngine().name).toLowerCase() || "" : this.getEngine().name || "";
}
/**
* Get parsed platform
* @return {{}}
*/
parseEngine() {
this.parsedResult.engine = {};
const e = n.find(ft, (r) => {
if (typeof r.test == "function")
return r.test(this);
if (r.test instanceof Array)
return r.test.some((s) => this.test(s));
throw new Error("Browser's test function is not valid");
});
return e && (this.parsedResult.engine = e.describe(this.getUA())), this.parsedResult.engine;
}
/**
* Parse full information about the browser
* @returns {Parser}
*/
parse() {
return this.parseBrowser(), this.parseOS(), this.parsePlatform(), this.parseEngine(), this;
}
/**
* Get parsed result
* @return {ParsedResult}
*/
getResult() {
return n.assign({}, this.parsedResult);
}
/**
* Check if parsed browser matches certain conditions
*
* @param {Object} checkTree It's one or two layered object,
* which can include a platform or an OS on the first layer
* and should have browsers