Bump version 2.0.4

This commit is contained in:
Faisal Salman 2025-06-21 21:41:00 +07:00
parent 86b3cd37e2
commit c9d008e97a
19 changed files with 251 additions and 134 deletions

View File

@ -65,6 +65,27 @@
--- ---
## Version 2.0.4
- Add new browser: Edge WebView, Edge WebView2
- Add new device vendor: Lava, Retroid, Vizio
- Add new OS: ArcaOS, Knoppix, Xubuntu, Windows CE, Windows RT
- Improve device detection: Google Pixel & Pixelbook Series, HMD, Infinix, LG WebOS TV, Motorola, Nothing, OnePlus, Sony, Tecno
- Improve OS detection: AIX, Arch, Fuchsia, Haiku, HarmonyOS, Mint, MorphOS, Solaris, Windows
- Improve `withClientHints()` browser naming adjustments: `Microsoft Edge WebView2` => `Edge WebView2`
- Identify device that uses Firefox Reality / Wolvic as `xr`
- Identify device with large screen as `smarttv`
- Identify Windows CE & Windows RT as distinct OS variants
- `extensions` submodule:
- Remove lookbehind assertion to ensure regex compatibility
- Add new crawlers: ChatGLM, Daum, iAskBot, Onespot, Qwantbot, Startpage
- Add new emails: Apple's Mail, DaumMail, Polymail, ProtonMail, SparkDesktop, Zimbra, ZohoMail-Desktop
- Add new fetchers: Iframely, MistralAI-User, Perplexity-User
- Add new inApps: Discord, Evernote, Figma, Flipboard, Mattermost, Notion, Postman, Rambox, Rocket.Chat, Microsoft Teams, TikTok Lite, VS Code
- Add new libraries: AdobeAIR, aiohttp, nutch, httpx, urllib3
- `enum` submodule:
- Fix mistakenly placed `BLU` categorized as browser name instead of device vendor
## Version 2.0.3 ## Version 2.0.3
- Add new browser: Dooble, Ecosia, LG Browser, Otter, qutebrowser, Surf - Add new browser: Dooble, Ecosia, LG Browser, Otter, qutebrowser, Surf

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "ua-parser-js", "name": "ua-parser-js",
"version": "2.0.3", "version": "2.0.4",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ua-parser-js", "name": "ua-parser-js",
"version": "2.0.3", "version": "2.0.4",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",

View File

@ -1,7 +1,7 @@
{ {
"title": "UAParser.js", "title": "UAParser.js",
"name": "ua-parser-js", "name": "ua-parser-js",
"version": "2.0.3", "version": "2.0.4",
"author": "Faisal Salman <f@faisalman.com> (http://faisalman.com)", "author": "Faisal Salman <f@faisalman.com> (http://faisalman.com)",
"description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client Hints data. Supports browser & node.js environment", "description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client Hints data. Supports browser & node.js environment",
"keywords": [ "keywords": [

View File

@ -1,4 +1,4 @@
// Type definitions for Enums submodule of UAParser.js v2.0.3 // Type definitions for Enums submodule of UAParser.js v2.0.4
// Project: https://github.com/faisalman/ua-parser-js // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////// ///////////////////////////////////////////////
/* Enums for UAParser.js v2.0.3 /* Enums for UAParser.js v2.0.4
https://github.com/faisalman/ua-parser-js https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */

View File

@ -3,7 +3,7 @@
// Source: /src/enums/ua-parser-enums.js // Source: /src/enums/ua-parser-enums.js
/////////////////////////////////////////////// ///////////////////////////////////////////////
/* Enums for UAParser.js v2.0.3 /* Enums for UAParser.js v2.0.4
https://github.com/faisalman/ua-parser-js https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -25,7 +25,6 @@ const Browser = Object.freeze({
BAIDU: 'Baidu Browser', BAIDU: 'Baidu Browser',
BASILISK: 'Basilisk', BASILISK: 'Basilisk',
BLAZER: 'Blazer', BLAZER: 'Blazer',
BLU: 'BLU',
BOLT: 'Bolt', BOLT: 'Bolt',
BOWSER: 'Bowser', BOWSER: 'Bowser',
BRAVE: 'Brave', BRAVE: 'Brave',
@ -48,6 +47,8 @@ const Browser = Object.freeze({
DUCKDUCKGO: 'DuckDuckGo', DUCKDUCKGO: 'DuckDuckGo',
ECOSIA: 'Ecosia', ECOSIA: 'Ecosia',
EDGE: 'Edge', EDGE: 'Edge',
EDGE_WEBVIEW: 'Edge WebView',
EDGE_WEBVIEW2: 'Edge WebView2',
EPIPHANY: 'Epiphany', EPIPHANY: 'Epiphany',
FACEBOOK: 'Facebook', FACEBOOK: 'Facebook',
FALKON: 'Falkon', FALKON: 'Falkon',
@ -218,6 +219,7 @@ const Vendor = Object.freeze({
ATT: 'AT&T', ATT: 'AT&T',
BENQ: 'BenQ', BENQ: 'BenQ',
BLACKBERRY: 'BlackBerry', BLACKBERRY: 'BlackBerry',
BLU: 'BLU',
CAT: 'Cat', CAT: 'Cat',
DELL: 'Dell', DELL: 'Dell',
ENERGIZER: 'Energizer', ENERGIZER: 'Energizer',
@ -236,6 +238,7 @@ const Vendor = Object.freeze({
ITEL: 'itel', ITEL: 'itel',
JOLLA: 'Jolla', JOLLA: 'Jolla',
KOBO: 'Kobo', KOBO: 'Kobo',
LAVA: 'Lava',
LENOVO: 'Lenovo', LENOVO: 'Lenovo',
LG: 'LG', LG: 'LG',
MEIZU: 'Meizu', MEIZU: 'Meizu',
@ -256,6 +259,7 @@ const Vendor = Object.freeze({
PICO: 'Pico', PICO: 'Pico',
POLYTRON: 'Polytron', POLYTRON: 'Polytron',
REALME: 'Realme', REALME: 'Realme',
RETROID: 'Retroid',
RIM: 'RIM', RIM: 'RIM',
ROKU: 'Roku', ROKU: 'Roku',
SAMSUNG: 'Samsung', SAMSUNG: 'Samsung',
@ -270,6 +274,7 @@ const Vendor = Object.freeze({
TESLA: 'Tesla', TESLA: 'Tesla',
ULEFONE: 'Ulefone', ULEFONE: 'Ulefone',
VIVO: 'Vivo', VIVO: 'Vivo',
VIZIO: 'Vizio',
VODAFONE: 'Vodafone', VODAFONE: 'Vodafone',
XBOX: 'Xbox', XBOX: 'Xbox',
XIAOMI: 'Xiaomi', XIAOMI: 'Xiaomi',
@ -307,6 +312,7 @@ const OS = Object.freeze({
AMIGA_OS: 'Amiga OS', AMIGA_OS: 'Amiga OS',
ANDROID: 'Android', ANDROID: 'Android',
ANDROID_X86: 'Android-x86', ANDROID_X86: 'Android-x86',
ARCAOS: 'ArcaOS',
ARCH: 'Arch', ARCH: 'Arch',
BADA: 'Bada', BADA: 'Bada',
BEOS: 'BeOS', BEOS: 'BeOS',
@ -337,6 +343,7 @@ const OS = Object.freeze({
IOS: 'iOS', IOS: 'iOS',
JOLI: 'Joli', JOLI: 'Joli',
KAIOS: 'KaiOS', KAIOS: 'KaiOS',
KNOPPIX: 'Knoppix',
KUBUNTU: 'Kubuntu', KUBUNTU: 'Kubuntu',
LINPUS: 'Linpus', LINPUS: 'Linpus',
LINSPIRE: 'Linspire', LINSPIRE: 'Linspire',
@ -385,10 +392,13 @@ const OS = Object.freeze({
WATCHOS: 'watchOS', WATCHOS: 'watchOS',
WEBOS: 'WebOS', WEBOS: 'WebOS',
WINDOWS: 'Windows', WINDOWS: 'Windows',
WINDOWS_CE: 'Windows CE',
WINDOWS_IOT: 'Windows IoT', WINDOWS_IOT: 'Windows IoT',
WINDOWS_MOBILE: 'Windows Mobile', WINDOWS_MOBILE: 'Windows Mobile',
WINDOWS_PHONE: 'Windows Phone', WINDOWS_PHONE: 'Windows Phone',
WINDOWS_RT: 'Windows RT',
XBOX: 'Xbox', XBOX: 'Xbox',
XUBUNTU: 'Xubuntu',
ZENWALK: 'Zenwalk' ZENWALK: 'Zenwalk'
// TODO : test! // TODO : test!

View File

@ -1,4 +1,4 @@
// Type definitions for Helpers submodule of UAParser.js v2.0.3 // Type definitions for Helpers submodule of UAParser.js v2.0.4
// Project: https://github.com/faisalman/ua-parser-js // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////// ///////////////////////////////////////////////
/* Extensions for UAParser.js v2.0.3 /* Extensions for UAParser.js v2.0.4
https://github.com/faisalman/ua-parser-js https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */

View File

@ -3,7 +3,7 @@
// Source: /src/extensions/ua-parser-extensions.js // Source: /src/extensions/ua-parser-extensions.js
/////////////////////////////////////////////// ///////////////////////////////////////////////
/* Extensions for UAParser.js v2.0.3 /* Extensions for UAParser.js v2.0.4
https://github.com/faisalman/ua-parser-js https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -52,13 +52,15 @@ const Crawlers = Object.freeze({
// DuckDuckBot - http://duckduckgo.com/duckduckbot.html // DuckDuckBot - http://duckduckgo.com/duckduckbot.html
// FacebookBot - https://developers.facebook.com/docs/sharing/bot/ // FacebookBot - https://developers.facebook.com/docs/sharing/bot/
// GPTBot - https://platform.openai.com/docs/gptbot // GPTBot - https://platform.openai.com/docs/gptbot
// iAskBot - https://iask.ai
// LinkedInBot - http://www.linkedin.com // LinkedInBot - http://www.linkedin.com
// MJ12bot - https://mj12bot.com/ // MJ12bot - https://mj12bot.com/
// MojeekBot - https://www.mojeek.com/bot.html // MojeekBot - https://www.mojeek.com/bot.html
// Onespot - https://www.onespot.com/identifying-traffic.html
// OpenAI's SearchGPT - https://platform.openai.com/docs/bots // OpenAI's SearchGPT - https://platform.openai.com/docs/bots
// PerplexityBot - https://perplexity.ai/perplexitybot // PerplexityBot - https://perplexity.ai/perplexitybot
// SeznamBot - http://napoveda.seznam.cz/seznambot-intro // SeznamBot - http://napoveda.seznam.cz/seznambot-intro
/((?:adidx|ahrefs|amazon|bing|cc|dot|duckduck|exa|facebook|gpt|linkedin|mj12|mojeek|oai-search|perplexity|semrush|seznam)bot)\/([\w\.-]+)/i, /((?:adidx|ahrefs|amazon|bing|cc|dot|duckduck|exa|facebook|gpt|iask|linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|semrush|seznam)bot)\/([\w\.-]+)/i,
// Applebot - http://apple.com/go/applebot // Applebot - http://apple.com/go/applebot
/(applebot(?:-extended)?)\/?([\w\.]*)/i, /(applebot(?:-extended)?)\/?([\w\.]*)/i,
@ -72,6 +74,9 @@ const Crawlers = Object.freeze({
// Coc Coc Bot - https://help.coccoc.com/en/search-engine // Coc Coc Bot - https://help.coccoc.com/en/search-engine
/(coccocbot-(?:image|web))\/([\w\.]+)/i, /(coccocbot-(?:image|web))\/([\w\.]+)/i,
// Daum
/(daum(?:oa)?(?:-image)?)[ \/]([\w\.]+)/i,
// Facebook / Meta // Facebook / Meta
// https://developers.facebook.com/docs/sharing/webmasters/web-crawlers // https://developers.facebook.com/docs/sharing/webmasters/web-crawlers
/(facebook(?:externalhit|catalog)|meta-externalagent)\/([\w\.]+)/i, /(facebook(?:externalhit|catalog)|meta-externalagent)\/([\w\.]+)/i,
@ -82,6 +87,9 @@ const Crawlers = Object.freeze({
// Internet Archive (archive.org) // Internet Archive (archive.org)
/(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i, /(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i,
// Qwantbot - https://help.qwant.com/bot
/(qwantbot)[-\w]*\/?([\w\.]*)/i,
// SemrushBot - http://www.semrush.com/bot.html // SemrushBot - http://www.semrush.com/bot.html
/((?:semrush|splitsignal)bot[-abcfimostw]*)\/?([\w\.-]*)/i, /((?:semrush|splitsignal)bot[-abcfimostw]*)\/?([\w\.-]*)/i,
@ -97,8 +105,8 @@ const Crawlers = Object.freeze({
// Yeti (Naver) // Yeti (Naver)
/(yeti)\/([\w\.]+)/i, /(yeti)\/([\w\.]+)/i,
// aiHitBot / Diffbot / Linespider / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / Webzio-Extended / Screaming Frog SEO Spider / Timpibot / VelenPublicWebCrawler / YisouSpider / YouBot // aiHitBot / Diffbot / Linespider / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / Webzio-Extended / Screaming Frog SEO Spider / Startpage / Timpibot / VelenPublicWebCrawler / YisouSpider / YouBot
/((?:aihit|diff|timpi|you)bot|omgili(?:bot)?|openai image downloader|(?:magpie-|velenpublicweb)crawler|webzio-extended|(?:screaming frog seo |line|yisou)spider)\/?([\w\.]*)/i /((?:aihit|diff|timpi|you)bot|omgili(?:bot)?|openai image downloader|(?:magpie-|velenpublicweb)crawler|startpageprivateimageproxy|webzio-extended|(?:chatglm-|line|screaming frog seo |yisou)spider)\/?([\w\.]*)/i
], ],
[NAME, VERSION, [TYPE, CRAWLER]], [NAME, VERSION, [TYPE, CRAWLER]],
@ -208,9 +216,18 @@ const ExtraDevices = Object.freeze({
const Emails = Object.freeze({ const Emails = Object.freeze({
browser : [ browser : [
[ [
// Evolution / Kontact/KMail / [Microsoft/Mac] Outlook / Thunderbird // Evolution / Kontact/KMail[2] / [Microsoft/Mac] Outlook / Thunderbird
/(airmail|bluemail|emclient|evolution|foxmail|kmail2?|kontact|(?:microsoft |mac)?outlook(?:-express)?|navermailapp|(?!chrom.+)sparrow|thunderbird|yahoo)(?:m.+ail; |[\/ ])([\w\.]+)/i // Airmail / BlueMail / DaumMail / eMClient / Foxmail / NaverMailApp / Polymail
], [NAME, VERSION, [TYPE, EMAIL]] // ProtonMail / SparkDesktop / Sparrow / Yahoo! Mail / Zimbra / ZohoMail-Desktop
/((?:air|blue|daum|fox|poly|proton)mail|emclient|evolution|kmail2?|kontact|(?:microsoft |mac)?outlook(?:-express)?|navermailapp|(?!chrom.+)sparrow|sparkdesktop|thunderbird|yahoo|zohomail-desktop)(?:m.+ail; |[\/ ])([\w\.]+)/i,
// Apple's Mail
/(mail)\/([\w\.]+) cf/i
], [NAME, VERSION, [TYPE, EMAIL]], [
// Zimbra
/zdesktop\/([\w\.]+)/i
], [VERSION, [NAME, 'Zimbra'], [TYPE, EMAIL]]
] ]
}); });
@ -226,8 +243,11 @@ const Fetchers = Object.freeze({
// DuckAssistBot - https://duckduckgo.com/duckassistbot/ // DuckAssistBot - https://duckduckgo.com/duckassistbot/
// Better Uptime / BingPreview / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot // Better Uptime / BingPreview / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
// Google Site Verifier / Meta / Yahoo! Japan // Google Site Verifier / Meta / Yahoo! Japan
// Iframely - https://iframely.com/docs/about
// Perplexity-User - https://docs.perplexity.ai/guides/bots
// MistralAI-User - https://docs.mistral.ai/robots/
// Yandex Bots - https://yandex.com/bots // Yandex Bots - https://yandex.com/bots
/(ahrefssiteaudit|(?:bing|microsoft)preview|chatgpt-user|mastodon|(?:discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero)bot|google-site-verification|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|searchshop)|yadirectfetcher)\/([\w\.]+)/i, /(ahrefssiteaudit|(?:bing|microsoft)preview|(?:chatgpt|mistralai|perplexity)-user|mastodon|(?:discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero)bot|google-site-verification|iframely|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|searchshop)|yadirectfetcher)\/([\w\.]+)/i,
// Bluesky // Bluesky
/(bluesky) cardyb\/([\w\.]+)/i, /(bluesky) cardyb\/([\w\.]+)/i,
@ -261,13 +281,31 @@ const Fetchers = Object.freeze({
/////////////////// ///////////////////
const InApps = Object.freeze({ const InApps = Object.freeze({
browser : [ browser : [[
// Discord/Figma/Flipboard/Mattermost/Notion/Postman/Rambox/Rocket.Chat/Slack/Teams
/\b(discord|figma|mattermost|notion|postman|rambox|rocket.chat|slack|teams)\/([\w\.]+).+(electron\/|; ios)/i,
/(flipboard)\/([\w\.]+)/i
], [NAME, VERSION, [TYPE, INAPP]], [
// Evernote/Teams on mobile
/(evernote) win/i,
/(teams)mobile-(ios|and)/i
], [NAME, [TYPE, INAPP]], [
// Slack // Slack
[/(?:slack(?=.+electron|.+ios)|chatlyio)\/([\d\.]+)/i], /chatlyio\/([\d\.]+)/i],
[VERSION, [NAME, 'Slack'], [TYPE, INAPP]], [VERSION, [NAME, 'Slack'], [TYPE, INAPP]], [
// TikTok Lite
/ultralite app_version\/([\w\.]+)/i],
[VERSION, [NAME, 'TikTok Lite'], [TYPE, INAPP]], [
// VS Code
/\) code\/([\d\.]+).+electron\//i],
[VERSION, [NAME, 'VS Code'], [TYPE, INAPP]], [
// Yahoo! Japan // Yahoo! Japan
[/jp\.co\.yahoo\.(?:android\.yjtop|ipn\.appli)\/([\d\.]+)/i], /jp\.co\.yahoo\.(?:android\.yjtop|ipn\.appli)\/([\d\.]+)/i],
[VERSION, [NAME, 'Yahoo! Japan'], [TYPE, INAPP]] [VERSION, [NAME, 'Yahoo! Japan'], [TYPE, INAPP]]
] ]
}); });
@ -332,8 +370,10 @@ const Libraries = Object.freeze({
browser : [ browser : [
// Apache-HttpClient/Axios/go-http-client/got/GuzzleHttp/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/Scrapy/superagent // Apache-HttpClient/Axios/go-http-client/got/GuzzleHttp/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/Scrapy/superagent
[ [
/^(apache-httpclient|axios|(?:go|java)-http-client|got|guzzlehttp|java|libwww-perl|lua-resty-http|needle|node-(?:fetch|superagent)|okhttp|php-soap|postmanruntime|python-(?:urllib|requests)|scrapy)\/([\w\.]+)/i, /^(apache-httpclient|axios|(?:go|java)-http-client|got|guzzlehttp|java|libwww-perl|lua-resty-http|needle|node-(?:fetch|superagent)|okhttp|php-soap|postmanruntime|python-(?:httpx|urllib[23]?|requests)|scrapy)\/([\w\.]+)/i,
/(jsdom|(?<=\()java)\/([\w\.]+)/i /(adobeair|aiohttp|jsdom)\/([\w\.]+)/i,
/(nutch)-([\w\.-]+)(\(|$)/i,
/\((java)\/([\w\.]+)/i
], [NAME, VERSION, [TYPE, LIBRARY]] ], [NAME, VERSION, [TYPE, LIBRARY]]
] ]
}); });

View File

@ -1,4 +1,4 @@
// Type definitions for Helpers submodule of UAParser.js v2.0.3 // Type definitions for Helpers submodule of UAParser.js v2.0.4
// Project: https://github.com/faisalman/ua-parser-js // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////// ///////////////////////////////////////////////
/* Helpers for UAParser.js v2.0.3 /* Helpers for UAParser.js v2.0.4
https://github.com/faisalman/ua-parser-js https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */

View File

@ -3,7 +3,7 @@
// Source: /src/helpers/ua-parser-helpers.js // Source: /src/helpers/ua-parser-helpers.js
/////////////////////////////////////////////// ///////////////////////////////////////////////
/* Helpers for UAParser.js v2.0.3 /* Helpers for UAParser.js v2.0.4
https://github.com/faisalman/ua-parser-js https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -114,6 +114,9 @@ const isAIBot = (resultOrUA) => [
// You.com // You.com
'youbot', 'youbot',
// Zhipu AI
'chatglm-spider',
// Zyte // Zyte
'scrapy' 'scrapy'

View File

@ -1,4 +1,4 @@
// Type definitions for UAParser.js v2.0.3 // Type definitions for UAParser.js v2.0.4
// Project: https://github.com/faisalman/ua-parser-js // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
/* UAParser.js v2.0.3 /* UAParser.js v2.0.4
Copyright © 2012-2025 Faisal Salman <f@faisalman.com> Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
AGPLv3 License *//* AGPLv3 License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@ -19,7 +19,7 @@
// Constants // Constants
///////////// /////////////
var LIBVERSION = '2.0.3', var LIBVERSION = '2.0.4',
UA_MAX_LENGTH = 500, UA_MAX_LENGTH = 500,
USER_AGENT = 'user-agent', USER_AGENT = 'user-agent',
EMPTY = '', EMPTY = '',

View File

@ -3,7 +3,7 @@
// Source: /src/main/ua-parser.js // Source: /src/main/ua-parser.js
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
/* UAParser.js v2.0.3 /* UAParser.js v2.0.4
Copyright © 2012-2025 Faisal Salman <f@faisalman.com> Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
AGPLv3 License *//* AGPLv3 License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@ -21,7 +21,7 @@
// Constants // Constants
///////////// /////////////
var LIBVERSION = '2.0.3', var LIBVERSION = '2.0.4',
UA_MAX_LENGTH = 500, UA_MAX_LENGTH = 500,
USER_AGENT = 'user-agent', USER_AGENT = 'user-agent',
EMPTY = '', EMPTY = '',
@ -154,11 +154,11 @@
has = function (str1, str2) { has = function (str1, str2) {
if (typeof str1 === OBJ_TYPE && str1.length > 0) { if (typeof str1 === OBJ_TYPE && str1.length > 0) {
for (var i in str1) { for (var i in str1) {
if (lowerize(str1[i]) == lowerize(str2)) return true; if (lowerize(str2) == lowerize(str1[i])) return true;
} }
return false; return false;
} }
return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false; return isString(str1) ? lowerize(str2) == lowerize(str1) : false;
}, },
isExtensions = function (obj, deep) { isExtensions = function (obj, deep) {
for (var prop in obj) { for (var prop in obj) {
@ -249,17 +249,25 @@
// assign given value, ignore regex match // assign given value, ignore regex match
this[q[0]] = q[1]; this[q[0]] = q[1];
} }
} else if (q.length === 3) { } else if (q.length >= 3) {
// check whether function or regex // Check whether q[1] FUNCTION or REGEX
if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) { if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
if (q.length > 3) {
this[q[0]] = match ? q[1].apply(this, q.slice(2)) : undefined;
} else {
// call function (usually string mapper) // call function (usually string mapper)
this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
}
} else { } else {
if (q.length == 3) {
// sanitize match using given regex // sanitize match using given regex
this[q[0]] = match ? match.replace(q[1], q[2]) : undefined; this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
} } else if (q.length == 4) {
} else if (q.length === 4) {
this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
} else if (q.length > 4) {
this[q[0]] = match ? q[3].apply(this, [match.replace(q[1], q[2])].concat(q.slice(4))) : undefined;
}
}
} }
} else { } else {
this[q] = match ? match : undefined; this[q] = match ? match : undefined;
@ -294,16 +302,16 @@
var windowsVersionMap = { var windowsVersionMap = {
'ME' : '4.90', 'ME' : '4.90',
'NT 3.11' : 'NT3.51', 'NT 3.51': '3.51',
'NT 4.0' : 'NT4.0', 'NT 4.0': '4.0',
'2000' : 'NT 5.0', '2000' : ['5.0', '5.01'],
'XP' : ['NT 5.1', 'NT 5.2'], 'XP' : ['5.1', '5.2'],
'Vista' : 'NT 6.0', 'Vista' : '6.0',
'7' : 'NT 6.1', '7' : '6.1',
'8' : 'NT 6.2', '8' : '6.2',
'8.1' : 'NT 6.3', '8.1' : '6.3',
'10' : ['NT 6.4', 'NT 10.0'], '10' : ['6.4', '10.0'],
'RT' : 'ARM' 'NT' : ''
}, },
formFactorsMap = { formFactorsMap = {
@ -315,6 +323,18 @@
'xr' : ['VR', 'XR'], 'xr' : ['VR', 'XR'],
'?' : ['Desktop', 'Unknown'], '?' : ['Desktop', 'Unknown'],
'*' : undefined '*' : undefined
},
browserHintsMap = {
'Chrome' : 'Google Chrome',
'Edge' : 'Microsoft Edge',
'Edge WebView2' : 'Microsoft Edge WebView2',
'Chrome WebView': 'Android WebView',
'Chrome Headless':'HeadlessChrome',
'Huawei Browser': 'HuaweiBrowser',
'MIUI Browser' : 'Miui Browser',
'Opera Mobi' : 'OperaMobile',
'Yandex' : 'YaBrowser'
}; };
////////////// //////////////
@ -328,7 +348,9 @@
// Most common regardless engine // Most common regardless engine
/\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [ ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
/edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge /webview.+edge\/([\w\.]+)/i // Microsoft Edge
], [VERSION, [NAME, EDGE+' WebView']], [
/edg(?:e|ios|a)?\/([\w\.]+)/i
], [VERSION, [NAME, 'Edge']], [ ], [VERSION, [NAME, 'Edge']], [
// Presto based // Presto based
@ -420,7 +442,6 @@
// WebView // WebView
/((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
], [[NAME, FACEBOOK], VERSION, [TYPE, INAPP]], [ ], [[NAME, FACEBOOK], VERSION, [TYPE, INAPP]], [
/(Klarna)\/([\w\.]+)/i, // Klarna Shopping Browser for iOS & Android
/(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
/(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
/(daum)apps[\/ ]([\w\.]+)/i, // Daum App /(daum)apps[\/ ]([\w\.]+)/i, // Daum App
@ -428,7 +449,7 @@
/\b(line)\/([\w\.]+)\/iab/i, // Line App for Android /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
/(alipay)client\/([\w\.]+)/i, // Alipay /(alipay)client\/([\w\.]+)/i, // Alipay
/(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
/(instagram|snapchat)[\/ ]([-\w\.]+)/i // Instagram/Snapchat /(instagram|snapchat|klarna)[\/ ]([-\w\.]+)/i // Instagram/Snapchat/Klarna
], [NAME, VERSION, [TYPE, INAPP]], [ ], [NAME, VERSION, [TYPE, INAPP]], [
/\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
], [VERSION, [NAME, 'GSA'], [TYPE, INAPP]], [ ], [VERSION, [NAME, 'GSA'], [TYPE, INAPP]], [
@ -443,6 +464,9 @@
/headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
], [VERSION, [NAME, CHROME+' Headless']], [ ], [VERSION, [NAME, CHROME+' Headless']], [
/wv\).+chrome\/([\w\.]+).+edgw\//i // Edge WebView2
], [VERSION, [NAME, EDGE+' WebView2']], [
/ wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView / wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView
], [[NAME, CHROME+' WebView'], VERSION], [ ], [[NAME, CHROME+' WebView'], VERSION], [
@ -535,7 +559,7 @@
/\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i /\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i
], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [ ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [
/\b((?:s[cgp]h|gt|sm)-(?![lr])\w+|sc[g-]?[\d]+a?|galaxy nexus)/i, /\b((?:s[cgp]h|gt|sm)-(?![lr])\w+|sc[g-]?[\d]+a?|galaxy nexus)/i,
/samsung[- ]((?!sm-[lr])[-\w]+)/i, /samsung[- ]((?!sm-[lr]|browser)[-\w]+)/i,
/sec-(sgh\w+)/i /sec-(sgh\w+)/i
], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
@ -580,16 +604,22 @@
/ ([\w ]+) miui\/v?\d/i / ([\w ]+) miui\/v?\d/i
], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [ ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
// OnePlus
/droid.+; (cph2[3-6]\d[13579]|((gm|hd)19|(ac|be|in|kb)20|(d[en]|eb|le|mt)21|ne22)[0-2]\d|p[g-k]\w[1m]10)\b/i,
/(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
// OPPO // OPPO
/; (\w+) bui.+ oppo/i, /; (\w+) bui.+ oppo/i,
/\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
], [MODEL, [VENDOR, OPPO], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, OPPO], [TYPE, MOBILE]], [
/\b(opd2(\d{3}a?))(?: bui|\))/i /\b(opd2(\d{3}a?))(?: bui|\))/i
], [MODEL, [VENDOR, strMapper, { 'OnePlus' : ['304', '403', '203'], '*' : OPPO }], [TYPE, TABLET]], [ ], [MODEL, [VENDOR, strMapper, { 'OnePlus' : ['203', '304', '403', '404', '413', '415'], '*' : OPPO }], [TYPE, TABLET]], [
// BLU Vivo Series // BLU
/(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i /(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i // Vivo series
], [MODEL, [VENDOR, 'BLU'], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, 'BLU'], [TYPE, MOBILE]], [
// Vivo // Vivo
/; vivo (\w+)(?: bui|\))/i, /; vivo (\w+)(?: bui|\))/i,
/\b(v[12]\d{3}\w?[at])(?: bui|;)/i /\b(v[12]\d{3}\w?[at])(?: bui|;)/i
@ -599,10 +629,17 @@
/\b(rmx[1-3]\d{3})(?: bui|;|\))/i /\b(rmx[1-3]\d{3})(?: bui|;|\))/i
], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [
// Lenovo
/(ideatab[-\w ]+|602lv|d-42a|a101lv|a2109a|a3500-hv|s[56]000|pb-6505[my]|tb-?x?\d{3,4}(?:f[cu]|xu|[av])|yt\d?-[jx]?\d+[lfmx])( bui|;|\)|\/)/i,
/lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
/lenovo[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i
], [MODEL, [VENDOR, LENOVO], [TYPE, MOBILE]], [
// Motorola // Motorola
/\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i, /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,
/\bmot(?:orola)?[- ](\w*)/i, /\bmot(?:orola)?[- ]([\w\s]+)(\)| bui)/i,
/((?:moto(?! 360)[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i /((?:moto(?! 360)[-\w\(\) ]+|xt\d{3,4}[cgkosw\+]?[-\d]*|nexus 6)(?= bui|\)))/i
], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [
/\b(mz60\d|xoom[2 ]{0,2}) build\//i /\b(mz60\d|xoom[2 ]{0,2}) build\//i
], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [ ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [
@ -611,15 +648,10 @@
/((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i
], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [ ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [
/(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i, /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,
/\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch))(\w+)/i, /\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch|webos))(\w+)/i,
/\blg-?([\d\w]+) bui/i /\blg-?([\d\w]+) bui/i
], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [
// Lenovo
/(ideatab[-\w ]+|602lv|d-42a|a101lv|a2109a|a3500-hv|s[56]000|pb-6505[my]|tb-?x?\d{3,4}(?:f[cu]|xu|[av])|yt\d?-[jx]?\d+[lfmx])( bui|;|\)|\/)/i,
/lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
// Nokia // Nokia
/(nokia) (t[12][01])/i /(nokia) (t[12][01])/i
], [VENDOR, MODEL, [TYPE, TABLET]], [ ], [VENDOR, MODEL, [TYPE, TABLET]], [
@ -630,21 +662,19 @@
// Google // Google
/(pixel (c|tablet))\b/i // Google Pixel C/Tablet /(pixel (c|tablet))\b/i // Google Pixel C/Tablet
], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [ ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [
/droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel // Google Pixel
/droid.+;(?: google)? (g(01[13]a|020[aem]|025[jn]|1b60|1f8f|2ybb|4s1m|576d|5nz6|8hhn|8vou|a02099|c15s|d1yq|e2ae|ec77|gh2x|kv4x|p4bc|pj41|r83y|tt9q|ur25|wvk6)|pixel[\d ]*a?( pro)?( xl)?( fold)?( \(5g\))?)( bui|\))/i
], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
/(google) (pixelbook( go)?)/i
], [VENDOR, MODEL], [
// Sony // Sony
/droid.+; (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i /droid.+; (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-\w\w\d\d)(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i
], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
/sony tablet [ps]/i, /sony tablet [ps]/i,
/\b(?:sony)?sgp\w+(?: bui|\))/i /\b(?:sony)?sgp\w+(?: bui|\))/i
], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [ ], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [
// OnePlus
/ (kb2005|in20[12]5|be20[12][59])\b/i,
/(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
// Amazon // Amazon
/(alexa)webm/i, /(alexa)webm/i,
/(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i, // Kindle Fire without Silk / Echo Show /(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i, // Kindle Fire without Silk / Echo Show
@ -715,7 +745,7 @@
], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [
// Nothing // Nothing
/droid.+; (a(?:015|06[35]|142p?))/i /droid.+; (a(in)?(0(15|59|6[35])|142)p?)/i
], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [
// Archos // Archos
@ -726,17 +756,20 @@
/; (ac[3-6]\d\w{2,8})( b|\))/i /; (ac[3-6]\d\w{2,8})( b|\))/i
], [MODEL, [VENDOR, 'Archos'], [TYPE, MOBILE]], [ ], [MODEL, [VENDOR, 'Archos'], [TYPE, MOBILE]], [
// HMD
/; (n159v)/i
], [MODEL, [VENDOR, 'HMD'], [TYPE, MOBILE]], [
// MIXED // MIXED
/(imo) (tab \w+)/i, // IMO /(imo) (tab \w+)/i, // IMO
/(infinix) (x1101b?)/i // Infinix XPad /(infinix|tecno) (x1101b?|p904|dp(7c|8d|10a)( pro)?|p70[1-3]a?|p904|t1101)/i // Infinix XPad / Tecno
], [VENDOR, MODEL, [TYPE, TABLET]], [ ], [VENDOR, MODEL, [TYPE, TABLET]], [
/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|infinix|tecno|micromax|advan)[-_ ]?([-\w]*)/i, /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
// BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Infinix/Tecno/Micromax/Advan // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Tecno/Micromax/Advan
/; (blu|hmd|imo|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/TCL /; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
/(hp) ([\w ]+\w)/i, // HP iPAQ /(hp) ([\w ]+\w)/i, // HP iPAQ
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
/(lenovo)[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i, // Lenovo
/(oppo) ?([\w ]+) bui/i // OPPO /(oppo) ?([\w ]+) bui/i // OPPO
], [VENDOR, MODEL, [TYPE, MOBILE]], [ ], [VENDOR, MODEL, [TYPE, MOBILE]], [
@ -768,6 +801,7 @@
], [VENDOR, [TYPE, SMARTTV]], [ ], [VENDOR, [TYPE, SMARTTV]], [
/hbbtv.+maple;(\d+)/i /hbbtv.+maple;(\d+)/i
], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [ ], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [
/(vizio)(?: |.+model\/)(\w+-\w+)/i, // Vizio
/tcast.+(lg)e?. ([-\w]+)/i // LG SmartTV /tcast.+(lg)e?. ([-\w]+)/i // LG SmartTV
], [VENDOR, MODEL, [TYPE, SMARTTV]], [ ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
/(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i
@ -799,26 +833,27 @@
], [VENDOR, MODEL, [TYPE, SMARTTV]], [ ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
/hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [ ], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [
// SmartTV from Unidentified Vendors // SmartTV from Unidentified Vendors
/droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i /droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i
], [MODEL, [TYPE, SMARTTV]], [ ], [MODEL, [TYPE, SMARTTV]], [
/\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i /\b(android tv|smart[- ]?tv|opera tv|tv; rv:|large screen[\w ]+safari)\b/i
], [[TYPE, SMARTTV]], [ ], [[TYPE, SMARTTV]], [
/////////////////// ///////////////////
// CONSOLES // CONSOLES
/////////////////// ///////////////////
/(ouya)/i, // Ouya
/(nintendo) (\w+)/i // Nintendo
], [VENDOR, MODEL, [TYPE, CONSOLE]], [
/droid.+; (shield)( bui|\))/i // Nvidia Portable
], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
/(playstation \w+)/i // Playstation /(playstation \w+)/i // Playstation
], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [ ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
/\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [ ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
/(ouya)/i, // Ouya
/(nintendo) (\w+)/i, // Nintendo
/(retroid) (pocket ([^\)]+))/i // Retroid Pocket
], [VENDOR, MODEL, [TYPE, CONSOLE]], [
/droid.+; (shield)( bui|\))/i // Nvidia Portable
], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
/////////////////// ///////////////////
// WEARABLES // WEARABLES
@ -854,6 +889,8 @@
], [VENDOR, MODEL, [TYPE, XR]], [ ], [VENDOR, MODEL, [TYPE, XR]], [
/(quest( \d| pro)?s?).+vr/i // Meta Quest /(quest( \d| pro)?s?).+vr/i // Meta Quest
], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [ ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
/mobile vr; rv.+firefox/i // Unidentifiable VR device using Firefox Reality / Wolvic
], [[TYPE, XR]], [
/////////////////// ///////////////////
// EMBEDDED // EMBEDDED
@ -865,7 +902,7 @@
], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [ ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
/(homepod).+mac os/i // Apple HomePod /(homepod).+mac os/i // Apple HomePod
], [MODEL, [VENDOR, APPLE], [TYPE, EMBEDDED]], [ ], [MODEL, [VENDOR, APPLE], [TYPE, EMBEDDED]], [
/windows iot/i /windows iot/i // Unidentifiable embedded device using Windows IoT
], [[TYPE, EMBEDDED]], [ ], [[TYPE, EMBEDDED]], [
//////////////////// ////////////////////
@ -911,14 +948,17 @@
os : [[ os : [[
// Windows // Windows
/microsoft (windows) (vista|xp)/i // Windows (iTunes) /(windows nt) (6\.[23]); arm/i // Windows RT
], [[NAME, /N/, 'R'], [VERSION, strMapper, windowsVersionMap]], [
/(windows (?:phone|mobile|iot))(?: os)?[\/ ]?([\d\.]*( se)?)/i, // Windows IoT/Mobile/Phone
// Windows NT/3.1/95/98/ME/2000/XP/Vista/7/8/8.1/10/11
/(windows)[\/ ](1[01]|2000|3\.1|7|8(\.1)?|9[58]|me|server 20\d\d( r2)?|vista|xp)/i
], [NAME, VERSION], [
/windows nt ?([\d\.\)]*)(?!.+xbox)/i,
/\bwin(?=3| ?9|n)(?:nt| 9x )?([\d\.;]*)/i
], [[VERSION, /(;|\))/g, '', strMapper, windowsVersionMap], [NAME, WINDOWS]], [
/(windows ce)\/?([\d\.]*)/i // Windows CE
], [NAME, VERSION], [ ], [NAME, VERSION], [
/(windows (?:phone(?: os)?|mobile|iot))[\/ ]?([\d\.\w ]*)/i // Windows Phone
], [NAME, [VERSION, strMapper, windowsVersionMap]], [
/windows nt 6\.2; (arm)/i, // Windows RT
/windows[\/ ]([ntce\d\. ]+\w)(?!.+xbox)/i,
/(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i
], [[VERSION, strMapper, windowsVersionMap], [NAME, WINDOWS]], [
// iOS/macOS // iOS/macOS
/[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS /[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
@ -926,7 +966,7 @@
/cfnetwork\/.+darwin/i /cfnetwork\/.+darwin/i
], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [ ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
/(mac os x) ?([\w\. ]*)/i, /(mac os x) ?([\w\. ]*)/i,
/(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS /(macintosh|mac_powerpc\b)(?!.+(haiku|morphos))/i // Mac OS
], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [ ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
// Google Chromecast // Google Chromecast
@ -942,12 +982,13 @@
], [VERSION, [NAME, CHROMECAST]], [ ], [VERSION, [NAME, CHROMECAST]], [
// Mobile OSes // Mobile OSes
/droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS /droid ([\w\.]+)\b.+(android[- ]x86)/i // Android-x86
], [VERSION, NAME], [ ], [VERSION, NAME], [
/(ubuntu) ([\w\.]+) like android/i // Ubuntu Touch /(ubuntu) ([\w\.]+) like android/i // Ubuntu Touch
], [[NAME, /(.+)/, '$1 Touch'], VERSION], [ ], [[NAME, /(.+)/, '$1 Touch'], VERSION], [
/(harmonyos)[\/ ]?([\d\.]*)/i, // HarmonyOS
// Android/Blackberry/WebOS/QNX/Bada/RIM/KaiOS/Maemo/MeeGo/S40/Sailfish OS/OpenHarmony/Tizen // Android/Blackberry/WebOS/QNX/Bada/RIM/KaiOS/Maemo/MeeGo/S40/Sailfish OS/OpenHarmony/Tizen
/(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen|webos)\w*[-\/\.; ]?([\d\.]*)/i /(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen)\w*[-\/\.; ]?([\d\.]*)/i
], [NAME, VERSION], [ ], [NAME, VERSION], [
/\(bb(10);/i // BlackBerry 10 /\(bb(10);/i // BlackBerry 10
], [VERSION, [NAME, BLACKBERRY]], [ ], [VERSION, [NAME, BLACKBERRY]], [
@ -955,9 +996,12 @@
], [VERSION, [NAME, 'Symbian']], [ ], [VERSION, [NAME, 'Symbian']], [
/mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS
], [VERSION, [NAME, FIREFOX+' OS']], [ ], [VERSION, [NAME, FIREFOX+' OS']], [
/web0s;.+rt(tv)/i, /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i, // WebOS
/\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS /webos(?:[ \/]?|\.tv-20(?=2[2-9]))(\d[\d\.]*)/i
], [VERSION, [NAME, 'webOS']], [ ], [VERSION, [NAME, 'webOS']], [
/web0s;.+?(?:chr[o0]me|safari)\/(\d+)/i
// https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine
], [[VERSION, strMapper, {'25':'120','24':'108','23':'94','22':'87','6':'79','5':'68','4':'53','3':'38','2':'538','1':'537','*':'TV'}], [NAME, 'webOS']], [
/watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS /watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
], [VERSION, [NAME, 'watchOS']], [ ], [VERSION, [NAME, 'watchOS']], [
@ -977,20 +1021,20 @@
// Other // Other
/\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm
/(mint)[\/\(\) ]?(\w*)/i, // Mint /linux.+(mint)[\/\(\) ]?([\w\.]*)/i, // Mint
/(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux /(mageia|vectorlinux|fuchsia|arcaos|arch(?= ?linux))[;l ]([\d\.]*)/i, // Mageia/VectorLinux/Fuchsia/ArcaOS/Arch
/([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, /([kxln]?ubuntu|debian|suse|opensuse|gentoo|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire|knoppix)(?: gnu[\/ ]linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i,
// Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire // Ubuntu/Debian/SUSE/Gentoo/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire/Knoppix
/(hurd|linux)(?: arm\w*| x86\w*| ?)([\w\.]*)/i, // Hurd/Linux /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
/\b(aix)[; ]([1-9\.]{0,4})/i, // AIX
/(hurd|linux|morphos)(?: (?:arm|x86|ppc)\w*| ?)([\w\.]*)/i, // Hurd/Linux/MorphOS
/(gnu) ?([\w\.]*)/i, // GNU /(gnu) ?([\w\.]*)/i, // GNU
/\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly
/(haiku) (\w+)/i // Haiku /(haiku) ?(r\d)?/i // Haiku
], [NAME, VERSION], [ ], [NAME, VERSION], [
/(sunos) ?([\w\.\d]*)/i // Solaris /(sunos) ?([\d\.]*)/i // Solaris
], [[NAME, 'Solaris'], VERSION], [ ], [[NAME, 'Solaris'], VERSION], [
/((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris /\b(beos|os\/2|amigaos|openvms|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/OpenVMS/HP-UX/SerenityOS
/(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
/\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS
/(unix) ?([\w\.]*)/i // UNIX /(unix) ?([\w\.]*)/i // UNIX
], [NAME, VERSION] ], [NAME, VERSION]
] ]
@ -1224,20 +1268,19 @@
for (var i in brands) { for (var i in brands) {
var brandName = brands[i].brand || brands[i], var brandName = brands[i].brand || brands[i],
brandVersion = brands[i].version; brandVersion = brands[i].version;
if (this.itemType == UA_BROWSER && !/not.a.brand/i.test(brandName) && (!prevName || (/chrom/i.test(prevName) && brandName != CHROMIUM))) { if (this.itemType == UA_BROWSER &&
brandName = strMapper(brandName, { !/not.a.brand/i.test(brandName) &&
'Chrome' : 'Google Chrome', (!prevName ||
'Edge' : 'Microsoft Edge', (/Chrom/.test(prevName) && brandName != CHROMIUM) ||
'Chrome WebView' : 'Android WebView', (prevName == EDGE && /WebView2/.test(brandName))
'Chrome Headless' : 'HeadlessChrome', )) {
'Huawei Browser' : 'HuaweiBrowser', brandName = strMapper(brandName, browserHintsMap);
'MIUI Browser' : 'Miui Browser', prevName = this.get(NAME);
'Opera Mobi' : 'OperaMobile', if (!(prevName && !/Chrom/.test(prevName) && /Chrom/.test(brandName))) {
'Yandex' : 'YaBrowser'
});
this.set(NAME, brandName) this.set(NAME, brandName)
.set(VERSION, brandVersion) .set(VERSION, brandVersion)
.set(MAJOR, majorize(brandVersion)); .set(MAJOR, majorize(brandVersion));
}
prevName = brandName; prevName = brandName;
} }
if (this.itemType == UA_ENGINE && brandName == CHROMIUM) { if (this.itemType == UA_ENGINE && brandName == CHROMIUM) {