diff --git a/bower.json b/bower.json index 0d1dc6808..b9806cb09 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "ua-parser-js", - "version": "1.0.37", + "version": "1.0.38", "authors": [ "Faisal Salman " ], diff --git a/changelog.md b/changelog.md index cde1b0947..4c6939c26 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,12 @@ Version 1.0.x is basically the equivalent of version 0.7.x. See [#536](https://github.com/faisalman/ua-parser-js/issues/536) for the reason behind this confusion. +## Version 0.7.38 / 1.0.38 +- Fix error on getOS() when userAgentData.platform is undefined +- Add new browser: Opera GX, Twitter +- Improve browser detection: DuckDuckGo +- Improve device detection: OPPO Pad, Oculus Quest + ## Version 0.7.37 / 1.0.37 - Fix misidentified WebView token as device model - Increase UA_MAX_LENGTH to 500 diff --git a/dist/ua-parser.min.js b/dist/ua-parser.min.js index 21114c80f..c9d480af4 100644 --- a/dist/ua-parser.min.js +++ b/dist/ua-parser.min.js @@ -1,4 +1,4 @@ -/* UAParser.js v1.0.37 +/* UAParser.js v1.0.38 Copyright © 2012-2021 Faisal Salman MIT License */ -(function(window,undefined){"use strict";var LIBVERSION="1.0.37",EMPTY="",UNKNOWN="?",FUNC_TYPE="function",UNDEF_TYPE="undefined",OBJ_TYPE="object",STR_TYPE="string",MAJOR="major",MODEL="model",NAME="name",TYPE="type",VENDOR="vendor",VERSION="version",ARCHITECTURE="architecture",CONSOLE="console",MOBILE="mobile",TABLET="tablet",SMARTTV="smarttv",WEARABLE="wearable",EMBEDDED="embedded",UA_MAX_LENGTH=500;var AMAZON="Amazon",APPLE="Apple",ASUS="ASUS",BLACKBERRY="BlackBerry",BROWSER="Browser",CHROME="Chrome",EDGE="Edge",FIREFOX="Firefox",GOOGLE="Google",HUAWEI="Huawei",LG="LG",MICROSOFT="Microsoft",MOTOROLA="Motorola",OPERA="Opera",SAMSUNG="Samsung",SHARP="Sharp",SONY="Sony",XIAOMI="Xiaomi",ZEBRA="Zebra",FACEBOOK="Facebook",CHROMIUM_OS="Chromium OS",MAC_OS="Mac OS";var extend=function(regexes,extensions){var mergedRegexes={};for(var i in regexes){if(extensions[i]&&extensions[i].length%2===0){mergedRegexes[i]=extensions[i].concat(regexes[i])}else{mergedRegexes[i]=regexes[i]}}return mergedRegexes},enumerize=function(arr){var enums={};for(var i=0;i0){if(q.length===2){if(typeof q[1]==FUNC_TYPE){this[q[0]]=q[1].call(this,match)}else{this[q[0]]=q[1]}}else if(q.length===3){if(typeof q[1]===FUNC_TYPE&&!(q[1].exec&&q[1].test)){this[q[0]]=match?q[1].call(this,match,q[2]):undefined}else{this[q[0]]=match?match.replace(q[1],q[2]):undefined}}else if(q.length===4){this[q[0]]=match?q[3].call(this,match.replace(q[1],q[2])):undefined}}else{this[q]=match?match:undefined}}}}i+=2}},strMapper=function(str,map){for(var i in map){if(typeof map[i]===OBJ_TYPE&&map[i].length>0){for(var j=0;j2){_device[MODEL]="iPad";_device[TYPE]=TABLET}return _device};this.getEngine=function(){var _engine={};_engine[NAME]=undefined;_engine[VERSION]=undefined;rgxMapper.call(_engine,_ua,_rgxmap.engine);return _engine};this.getOS=function(){var _os={};_os[NAME]=undefined;_os[VERSION]=undefined;rgxMapper.call(_os,_ua,_rgxmap.os);if(_isSelfNav&&!_os[NAME]&&_uach&&_uach.platform!="Unknown"){_os[NAME]=_uach.platform.replace(/chrome os/i,CHROMIUM_OS).replace(/macos/i,MAC_OS)}return _os};this.getResult=function(){return{ua:this.getUA(),browser:this.getBrowser(),engine:this.getEngine(),os:this.getOS(),device:this.getDevice(),cpu:this.getCPU()}};this.getUA=function(){return _ua};this.setUA=function(ua){_ua=typeof ua===STR_TYPE&&ua.length>UA_MAX_LENGTH?trim(ua,UA_MAX_LENGTH):ua;return this};this.setUA(_ua);return this};UAParser.VERSION=LIBVERSION;UAParser.BROWSER=enumerize([NAME,VERSION,MAJOR]);UAParser.CPU=enumerize([ARCHITECTURE]);UAParser.DEVICE=enumerize([MODEL,VENDOR,TYPE,CONSOLE,MOBILE,SMARTTV,TABLET,WEARABLE,EMBEDDED]);UAParser.ENGINE=UAParser.OS=enumerize([NAME,VERSION]);if(typeof exports!==UNDEF_TYPE){if(typeof module!==UNDEF_TYPE&&module.exports){exports=module.exports=UAParser}exports.UAParser=UAParser}else{if(typeof define===FUNC_TYPE&&define.amd){define(function(){return UAParser})}else if(typeof window!==UNDEF_TYPE){window.UAParser=UAParser}}var $=typeof window!==UNDEF_TYPE&&(window.jQuery||window.Zepto);if($&&!$.ua){var parser=new UAParser;$.ua=parser.getResult();$.ua.get=function(){return parser.getUA()};$.ua.set=function(ua){parser.setUA(ua);var result=parser.getResult();for(var prop in result){$.ua[prop]=result[prop]}}}})(typeof window==="object"?window:this); \ No newline at end of file +(function(window,undefined){"use strict";var LIBVERSION="1.0.38",EMPTY="",UNKNOWN="?",FUNC_TYPE="function",UNDEF_TYPE="undefined",OBJ_TYPE="object",STR_TYPE="string",MAJOR="major",MODEL="model",NAME="name",TYPE="type",VENDOR="vendor",VERSION="version",ARCHITECTURE="architecture",CONSOLE="console",MOBILE="mobile",TABLET="tablet",SMARTTV="smarttv",WEARABLE="wearable",EMBEDDED="embedded",UA_MAX_LENGTH=500;var AMAZON="Amazon",APPLE="Apple",ASUS="ASUS",BLACKBERRY="BlackBerry",BROWSER="Browser",CHROME="Chrome",EDGE="Edge",FIREFOX="Firefox",GOOGLE="Google",HUAWEI="Huawei",LG="LG",MICROSOFT="Microsoft",MOTOROLA="Motorola",OPERA="Opera",SAMSUNG="Samsung",SHARP="Sharp",SONY="Sony",XIAOMI="Xiaomi",ZEBRA="Zebra",FACEBOOK="Facebook",CHROMIUM_OS="Chromium OS",MAC_OS="Mac OS";var extend=function(regexes,extensions){var mergedRegexes={};for(var i in regexes){if(extensions[i]&&extensions[i].length%2===0){mergedRegexes[i]=extensions[i].concat(regexes[i])}else{mergedRegexes[i]=regexes[i]}}return mergedRegexes},enumerize=function(arr){var enums={};for(var i=0;i0){if(q.length===2){if(typeof q[1]==FUNC_TYPE){this[q[0]]=q[1].call(this,match)}else{this[q[0]]=q[1]}}else if(q.length===3){if(typeof q[1]===FUNC_TYPE&&!(q[1].exec&&q[1].test)){this[q[0]]=match?q[1].call(this,match,q[2]):undefined}else{this[q[0]]=match?match.replace(q[1],q[2]):undefined}}else if(q.length===4){this[q[0]]=match?q[3].call(this,match.replace(q[1],q[2])):undefined}}else{this[q]=match?match:undefined}}}}i+=2}},strMapper=function(str,map){for(var i in map){if(typeof map[i]===OBJ_TYPE&&map[i].length>0){for(var j=0;j2){_device[MODEL]="iPad";_device[TYPE]=TABLET}return _device};this.getEngine=function(){var _engine={};_engine[NAME]=undefined;_engine[VERSION]=undefined;rgxMapper.call(_engine,_ua,_rgxmap.engine);return _engine};this.getOS=function(){var _os={};_os[NAME]=undefined;_os[VERSION]=undefined;rgxMapper.call(_os,_ua,_rgxmap.os);if(_isSelfNav&&!_os[NAME]&&_uach&&_uach.platform&&_uach.platform!="Unknown"){_os[NAME]=_uach.platform.replace(/chrome os/i,CHROMIUM_OS).replace(/macos/i,MAC_OS)}return _os};this.getResult=function(){return{ua:this.getUA(),browser:this.getBrowser(),engine:this.getEngine(),os:this.getOS(),device:this.getDevice(),cpu:this.getCPU()}};this.getUA=function(){return _ua};this.setUA=function(ua){_ua=typeof ua===STR_TYPE&&ua.length>UA_MAX_LENGTH?trim(ua,UA_MAX_LENGTH):ua;return this};this.setUA(_ua);return this};UAParser.VERSION=LIBVERSION;UAParser.BROWSER=enumerize([NAME,VERSION,MAJOR]);UAParser.CPU=enumerize([ARCHITECTURE]);UAParser.DEVICE=enumerize([MODEL,VENDOR,TYPE,CONSOLE,MOBILE,SMARTTV,TABLET,WEARABLE,EMBEDDED]);UAParser.ENGINE=UAParser.OS=enumerize([NAME,VERSION]);if(typeof exports!==UNDEF_TYPE){if(typeof module!==UNDEF_TYPE&&module.exports){exports=module.exports=UAParser}exports.UAParser=UAParser}else{if(typeof define===FUNC_TYPE&&define.amd){define(function(){return UAParser})}else if(typeof window!==UNDEF_TYPE){window.UAParser=UAParser}}var $=typeof window!==UNDEF_TYPE&&(window.jQuery||window.Zepto);if($&&!$.ua){var parser=new UAParser;$.ua=parser.getResult();$.ua.get=function(){return parser.getUA()};$.ua.set=function(ua){parser.setUA(ua);var result=parser.getResult();for(var prop in result){$.ua[prop]=result[prop]}}}})(typeof window==="object"?window:this); \ No newline at end of file diff --git a/dist/ua-parser.pack.js b/dist/ua-parser.pack.js index c4abae98b..3e33f538a 100644 --- a/dist/ua-parser.pack.js +++ b/dist/ua-parser.pack.js @@ -1,4 +1,4 @@ -/* UAParser.js v1.0.37 +/* UAParser.js v1.0.38 Copyright © 2012-2021 Faisal Salman MIT License */ -!function(s,l){"use strict";function i(i){for(var e={},o=0;o (http://faisalman.com)", "description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Supports browser & node.js environment", "keywords": [ diff --git a/readme.md b/readme.md index a92e0f914..9e8909703 100644 --- a/readme.md +++ b/readme.md @@ -108,13 +108,13 @@ Iceweasel, Instagram, Iridium, Iron, Jasmine, Kakao[Story/Talk], K-Meleon, Kindle, Klar, Klarna, Konqueror, LBBROWSER, Line, LinkedIn, Links, Lunascape, Lynx, MIUI Browser, Maemo, Maxthon, Midori, Minimo, Mobile Safari, Mosaic, Mozilla, NetFront, NetSurf, Netfront, Netscape, NokiaBrowser, Obigo, -Oculus Browser, OmniWeb, Opera Coast, Opera [Mini/Mobi/Tablet], PaleMoon, +Oculus Browser, OmniWeb, Opera Coast, Opera [GX/Mini/Mobi/Tablet], PaleMoon, PhantomJS, Phoenix, Polaris, Puffin, QQ, QQBrowser, QQBrowserLite, Quark, QupZilla, RockMelt, Safari, Sailfish Browser, Samsung Internet, SeaMonkey, Silk, Skyfire, Sleipnir, Slim, SlimBrowser, Smart Lenovo Browser, Snapchat, -Sogou [Explorer/Mobile], Swiftfox, Tesla, TikTok, Tizen Browser, UCBrowser, -UP.Browser, Viera, Vivaldi, Vivo Browser, Waterfox, WeChat, Weibo, Yandex, w3m, -Whale Browser, ... +Sogou [Explorer/Mobile], Swiftfox, Tesla, TikTok, Tizen Browser, Twitter, +UCBrowser, UP.Browser, Viera, Vivaldi, Vivo Browser, Waterfox, WeChat, Weibo, +Yandex, w3m, Whale Browser, ... # 'browser.version' determined dynamically ``` diff --git a/src/ua-parser.js b/src/ua-parser.js index 5a61df234..1f5f9cab4 100755 --- a/src/ua-parser.js +++ b/src/ua-parser.js @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////////// -/* UAParser.js v1.0.37 +/* UAParser.js v1.0.38 Copyright © 2012-2021 Faisal Salman MIT License *//* Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. @@ -17,7 +17,7 @@ ///////////// - var LIBVERSION = '1.0.37', + var LIBVERSION = '1.0.38', EMPTY = '', UNKNOWN = '?', FUNC_TYPE = 'function', @@ -223,6 +223,8 @@ ], [NAME, VERSION], [ /opios[\/ ]+([\w\.]+)/i // Opera mini on iphone >= 8.0 ], [VERSION, [NAME, OPERA+' Mini']], [ + /\bop(?:rg)?x\/([\w\.]+)/i // Opera GX + ], [VERSION, [NAME, OPERA+' GX']], [ /\bopr\/([\w\.]+)/i // Opera Webkit ], [VERSION, [NAME, OPERA]], [ @@ -241,6 +243,8 @@ /(heytap|ovi)browser\/([\d\.]+)/i, // Heytap/Ovi /(weibo)__([\d\.]+)/i // Weibo ], [NAME, VERSION], [ + /\bddg\/([\w\.]+)/i // DuckDuckGo + ], [VERSION, [NAME, 'DuckDuckGo']], [ /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i // UCBrowser ], [VERSION, [NAME, 'UC'+BROWSER]], [ /microm.+\bqbcore\/([\w\.]+)/i, // WeChat Desktop for Windows Built-in Browser @@ -300,6 +304,7 @@ /safari (line)\/([\w\.]+)/i, // Line App for iOS /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android /(alipay)client\/([\w\.]+)/i, // Alipay + /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter /(chromium|instagram|snapchat)[\/ ]([-\w\.]+)/i // Chromium/Instagram/Snapchat ], [NAME, VERSION], [ /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS @@ -437,6 +442,8 @@ /; (\w+) bui.+ oppo/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]], [ + /\b(opd2\d{3}a?) bui/i + ], [MODEL, [VENDOR, 'OPPO'], [TYPE, TABLET]], [ // Vivo /vivo (\w+)(?: bui|\))/i, @@ -673,7 +680,7 @@ ], [MODEL, [VENDOR, GOOGLE], [TYPE, WEARABLE]], [ /droid.+; (wt63?0{2,3})\)/i ], [MODEL, [VENDOR, ZEBRA], [TYPE, WEARABLE]], [ - /(quest( 2| pro)?)/i // Oculus Quest + /(quest( \d| pro)?)/i // Oculus Quest ], [MODEL, [VENDOR, FACEBOOK], [TYPE, WEARABLE]], [ /////////////////// @@ -865,7 +872,7 @@ _os[NAME] = undefined; _os[VERSION] = undefined; rgxMapper.call(_os, _ua, _rgxmap.os); - if (_isSelfNav && !_os[NAME] && _uach && _uach.platform != 'Unknown') { + if (_isSelfNav && !_os[NAME] && _uach && _uach.platform && _uach.platform != 'Unknown') { _os[NAME] = _uach.platform .replace(/chrome os/i, CHROMIUM_OS) .replace(/macos/i, MAC_OS); // backward compatibility diff --git a/test/browser-test.json b/test/browser-test.json index 0edf59059..79f965f50 100644 --- a/test/browser-test.json +++ b/test/browser-test.json @@ -419,6 +419,16 @@ "major" : "1" } }, + { + "desc" : "DuckDuckGo", + "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.1517.4.1 Ddg/17.4.1", + "expect" : + { + "name" : "DuckDuckGo", + "version" : "17.4.1", + "major" : "17" + } + }, { "desc" : "DuckDuckGo", "ua" : "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/92.0.4515.131 Mobile DuckDuckGo/5 Safari/537.36", @@ -1118,6 +1128,26 @@ "major" : "12" } }, + { + "desc" : "Opera GX on Android", + "ua" : "Mozilla/5.0 (Linux; Android 10; Redmi Note 8 Pro Build/QP1A.190711.020) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.168 Mobile Safari/537.36 OPX/2", + "expect" : + { + "name" : "Opera GX", + "version" : "2", + "major" : "2" + } + }, + { + "desc" : "Opera GX on Windows", + "ua" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.50747 OPRGX/60.0.3255.50747", + "expect" : + { + "name" : "Opera GX", + "version" : "60.0.3255.50747", + "major" : "60" + } + }, { "desc" : "Opera Tablet", "ua" : "Opera/9.80 (Windows NT 6.1; Opera Tablet/15165; U; en) Presto/2.8.149 Version/11.1", @@ -2011,5 +2041,25 @@ "version" : "12.33.0.36", "major" : "12" } + }, + { + "desc" : "Twitter", + "ua" : "Mozilla/5.0 (Linux; Android 13; CPH2531 Build/SP1A.210812.016; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/123.0.6312.120 Mobile Safari/537.36 TwitterAndroid", + "expect" : + { + "name" : "Twitter", + "version" : "undefined", + "major" : "undefined" + } + }, + { + "desc" : "Twitter", + "ua" : "Mozilla/5.0 (iPad; CPU OS 15_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/19H12 Twitter for iPhone/10.34", + "expect" : + { + "name" : "Twitter", + "version" : "10.34", + "major" : "10" + } } ] diff --git a/test/device-test.json b/test/device-test.json index 18eae2038..d719533cf 100644 --- a/test/device-test.json +++ b/test/device-test.json @@ -1376,6 +1376,15 @@ "type": "wearable" } }, + { + "desc": "Oculus Quest 3", + "ua": "Mozilla/5.0 (X11; Linux x86_64; Quest 3) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/31.4.0.6.51.566757996 Chrome/120.0.6099.283 VR Safari/537.36", + "expect": { + "vendor": "Facebook", + "model": "Quest 3", + "type": "wearable" + } + }, { "desc": "Oculus Quest Pro", "ua": "Mozilla/5.0 (X11; Linux x86_64; Quest Pro) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/24.4.0.22.60.426469926 SamsungBrowser/4.0 Chrome/106.0.5249.181 VR Safari/537.36", @@ -1493,6 +1502,15 @@ "type": "mobile" } }, + { + "desc": "OPPO Pad", + "ua": "Mozilla/5.0 (Linux; U; Android 13; zh-CN; OPD2101 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.58 UCBrowser/16.3.9.1290 Mobile Safari/537.36", + "expect": { + "vendor": "OPPO", + "model": "OPD2101", + "type": "tablet" + } + }, { "desc": "OPPO Neo", "ua": "Mozilla/5.0 (Linux; U; Android 4.2.2; zh-cn; R831T Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 OppoBrowser/3.3.2 Mobile Safari/534.30",