ua-parser-js 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v2.0.2
3
- Copyright © 2012-2024 Faisal Salman <f@faisalman.com>
2
+ /* UAParser.js v2.0.4
3
+ Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
4
4
  AGPLv3 License *//*
5
5
  Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
6
6
  Supports browser & node.js environment.
@@ -19,7 +19,7 @@
19
19
  // Constants
20
20
  /////////////
21
21
 
22
- var LIBVERSION = '2.0.2',
22
+ var LIBVERSION = '2.0.4',
23
23
  UA_MAX_LENGTH = 500,
24
24
  USER_AGENT = 'user-agent',
25
25
  EMPTY = '',
@@ -152,11 +152,11 @@
152
152
  has = function (str1, str2) {
153
153
  if (typeof str1 === OBJ_TYPE && str1.length > 0) {
154
154
  for (var i in str1) {
155
- if (lowerize(str1[i]) == lowerize(str2)) return true;
155
+ if (lowerize(str2) == lowerize(str1[i])) return true;
156
156
  }
157
157
  return false;
158
158
  }
159
- return isString(str1) ? lowerize(str2).indexOf(lowerize(str1)) !== -1 : false;
159
+ return isString(str1) ? lowerize(str2) == lowerize(str1) : false;
160
160
  },
161
161
  isExtensions = function (obj, deep) {
162
162
  for (var prop in obj) {
@@ -247,17 +247,25 @@
247
247
  // assign given value, ignore regex match
248
248
  this[q[0]] = q[1];
249
249
  }
250
- } else if (q.length === 3) {
251
- // check whether function or regex
250
+ } else if (q.length >= 3) {
251
+ // Check whether q[1] FUNCTION or REGEX
252
252
  if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
253
- // call function (usually string mapper)
254
- this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
253
+ if (q.length > 3) {
254
+ this[q[0]] = match ? q[1].apply(this, q.slice(2)) : undefined;
255
+ } else {
256
+ // call function (usually string mapper)
257
+ this[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
258
+ }
255
259
  } else {
256
- // sanitize match using given regex
257
- this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
260
+ if (q.length == 3) {
261
+ // sanitize match using given regex
262
+ this[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
263
+ } else if (q.length == 4) {
264
+ this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
265
+ } else if (q.length > 4) {
266
+ this[q[0]] = match ? q[3].apply(this, [match.replace(q[1], q[2])].concat(q.slice(4))) : undefined;
267
+ }
258
268
  }
259
- } else if (q.length === 4) {
260
- this[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
261
269
  }
262
270
  } else {
263
271
  this[q] = match ? match : undefined;
@@ -291,17 +299,17 @@
291
299
  //////////////
292
300
 
293
301
  var windowsVersionMap = {
294
- 'ME' : '4.90',
295
- 'NT 3.11' : 'NT3.51',
296
- 'NT 4.0' : 'NT4.0',
297
- '2000' : 'NT 5.0',
298
- 'XP' : ['NT 5.1', 'NT 5.2'],
299
- 'Vista' : 'NT 6.0',
300
- '7' : 'NT 6.1',
301
- '8' : 'NT 6.2',
302
- '8.1' : 'NT 6.3',
303
- '10' : ['NT 6.4', 'NT 10.0'],
304
- 'RT' : 'ARM'
302
+ 'ME' : '4.90',
303
+ 'NT 3.51': '3.51',
304
+ 'NT 4.0': '4.0',
305
+ '2000' : ['5.0', '5.01'],
306
+ 'XP' : ['5.1', '5.2'],
307
+ 'Vista' : '6.0',
308
+ '7' : '6.1',
309
+ '8' : '6.2',
310
+ '8.1' : '6.3',
311
+ '10' : ['6.4', '10.0'],
312
+ 'NT' : ''
305
313
  },
306
314
 
307
315
  formFactorsMap = {
@@ -313,6 +321,18 @@
313
321
  'xr' : ['VR', 'XR'],
314
322
  '?' : ['Desktop', 'Unknown'],
315
323
  '*' : undefined
324
+ },
325
+
326
+ browserHintsMap = {
327
+ 'Chrome' : 'Google Chrome',
328
+ 'Edge' : 'Microsoft Edge',
329
+ 'Edge WebView2' : 'Microsoft Edge WebView2',
330
+ 'Chrome WebView': 'Android WebView',
331
+ 'Chrome Headless':'HeadlessChrome',
332
+ 'Huawei Browser': 'HuaweiBrowser',
333
+ 'MIUI Browser' : 'Miui Browser',
334
+ 'Opera Mobi' : 'OperaMobile',
335
+ 'Yandex' : 'YaBrowser'
316
336
  };
317
337
 
318
338
  //////////////
@@ -326,7 +346,9 @@
326
346
  // Most common regardless engine
327
347
  /\b(?:crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
328
348
  ], [VERSION, [NAME, PREFIX_MOBILE + 'Chrome']], [
329
- /edg(?:e|ios|a)?\/([\w\.]+)/i // Microsoft Edge
349
+ /webview.+edge\/([\w\.]+)/i // Microsoft Edge
350
+ ], [VERSION, [NAME, EDGE+' WebView']], [
351
+ /edg(?:e|ios|a)?\/([\w\.]+)/i
330
352
  ], [VERSION, [NAME, 'Edge']], [
331
353
 
332
354
  // Presto based
@@ -353,11 +375,11 @@
353
375
  /(avant|iemobile|slim(?:browser|boat|jet))[\/ ]?([\d\.]*)/i, // Avant/IEMobile/SlimBrowser/SlimBoat/Slimjet
354
376
  /(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
355
377
 
356
- // Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon
357
- /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon)\/([-\w\.]+)/i,
378
+ // Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble
379
+ /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser)\/([-\w\.]+)/i,
358
380
  // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
359
- /(heytap|ovi|115)browser\/([\d\.]+)/i, // HeyTap/Ovi/115
360
- /(weibo)__([\d\.]+)/i // Weibo
381
+ /(heytap|ovi|115|surf)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
382
+ /(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
361
383
  ], [NAME, VERSION], [
362
384
  /quark(?:pc)?\/([-\w\.]+)/i // Quark
363
385
  ], [VERSION, [NAME, 'Quark']], [
@@ -418,7 +440,6 @@
418
440
  // WebView
419
441
  /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i // Facebook App for iOS & Android
420
442
  ], [[NAME, FACEBOOK], VERSION, [TYPE, INAPP]], [
421
- /(Klarna)\/([\w\.]+)/i, // Klarna Shopping Browser for iOS & Android
422
443
  /(kakao(?:talk|story))[\/ ]([\w\.]+)/i, // Kakao App
423
444
  /(naver)\(.*?(\d+\.[\w\.]+).*\)/i, // Naver InApp
424
445
  /(daum)apps[\/ ]([\w\.]+)/i, // Daum App
@@ -426,7 +447,7 @@
426
447
  /\b(line)\/([\w\.]+)\/iab/i, // Line App for Android
427
448
  /(alipay)client\/([\w\.]+)/i, // Alipay
428
449
  /(twitter)(?:and| f.+e\/([\w\.]+))/i, // Twitter
429
- /(instagram|snapchat)[\/ ]([-\w\.]+)/i // Instagram/Snapchat
450
+ /(instagram|snapchat|klarna)[\/ ]([-\w\.]+)/i // Instagram/Snapchat/Klarna
430
451
  ], [NAME, VERSION, [TYPE, INAPP]], [
431
452
  /\bgsa\/([\w\.]+) .*safari\//i // Google Search Appliance on iOS
432
453
  ], [VERSION, [NAME, 'GSA'], [TYPE, INAPP]], [
@@ -441,6 +462,9 @@
441
462
  /headlesschrome(?:\/([\w\.]+)| )/i // Chrome Headless
442
463
  ], [VERSION, [NAME, CHROME+' Headless']], [
443
464
 
465
+ /wv\).+chrome\/([\w\.]+).+edgw\//i // Edge WebView2
466
+ ], [VERSION, [NAME, EDGE+' WebView2']], [
467
+
444
468
  / wv\).+(chrome)\/([\w\.]+)/i // Chrome WebView
445
469
  ], [[NAME, CHROME+' WebView'], VERSION], [
446
470
 
@@ -533,7 +557,7 @@
533
557
  /\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
534
558
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, TABLET]], [
535
559
  /\b((?:s[cgp]h|gt|sm)-(?![lr])\w+|sc[g-]?[\d]+a?|galaxy nexus)/i,
536
- /samsung[- ]((?!sm-[lr])[-\w]+)/i,
560
+ /samsung[- ]((?!sm-[lr]|browser)[-\w]+)/i,
537
561
  /sec-(sgh\w+)/i
538
562
  ], [MODEL, [VENDOR, SAMSUNG], [TYPE, MOBILE]], [
539
563
 
@@ -578,15 +602,24 @@
578
602
  / ([\w ]+) miui\/v?\d/i
579
603
  ], [[MODEL, /_/g, ' '], [VENDOR, XIAOMI], [TYPE, MOBILE]], [
580
604
 
605
+ // OnePlus
606
+ /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,
607
+ /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
608
+ ], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
609
+
581
610
  // OPPO
582
611
  /; (\w+) bui.+ oppo/i,
583
612
  /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i
584
613
  ], [MODEL, [VENDOR, OPPO], [TYPE, MOBILE]], [
585
614
  /\b(opd2(\d{3}a?))(?: bui|\))/i
586
- ], [MODEL, [VENDOR, strMapper, { 'OnePlus' : ['304', '403', '203'], '*' : OPPO }], [TYPE, TABLET]], [
615
+ ], [MODEL, [VENDOR, strMapper, { 'OnePlus' : ['203', '304', '403', '404', '413', '415'], '*' : OPPO }], [TYPE, TABLET]], [
616
+
617
+ // BLU
618
+ /(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i // Vivo series
619
+ ], [MODEL, [VENDOR, 'BLU'], [TYPE, MOBILE]], [
587
620
 
588
621
  // Vivo
589
- /vivo (\w+)(?: bui|\))/i,
622
+ /; vivo (\w+)(?: bui|\))/i,
590
623
  /\b(v[12]\d{3}\w?[at])(?: bui|;)/i
591
624
  ], [MODEL, [VENDOR, 'Vivo'], [TYPE, MOBILE]], [
592
625
 
@@ -594,10 +627,17 @@
594
627
  /\b(rmx[1-3]\d{3})(?: bui|;|\))/i
595
628
  ], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [
596
629
 
630
+ // Lenovo
631
+ /(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,
632
+ /lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
633
+ ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
634
+ /lenovo[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i
635
+ ], [MODEL, [VENDOR, LENOVO], [TYPE, MOBILE]], [
636
+
597
637
  // Motorola
598
638
  /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,
599
- /\bmot(?:orola)?[- ](\w*)/i,
600
- /((?:moto(?! 360)[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i
639
+ /\bmot(?:orola)?[- ]([\w\s]+)(\)| bui)/i,
640
+ /((?:moto(?! 360)[-\w\(\) ]+|xt\d{3,4}[cgkosw\+]?[-\d]*|nexus 6)(?= bui|\)))/i
601
641
  ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [
602
642
  /\b(mz60\d|xoom[2 ]{0,2}) build\//i
603
643
  ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [
@@ -606,15 +646,10 @@
606
646
  /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i
607
647
  ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [
608
648
  /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,
609
- /\blg[-e;\/ ]+((?!browser|netcast|android tv|watch)\w+)/i,
649
+ /\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch|webos))(\w+)/i,
610
650
  /\blg-?([\d\w]+) bui/i
611
651
  ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [
612
652
 
613
- // Lenovo
614
- /(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,
615
- /lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
616
- ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
617
-
618
653
  // Nokia
619
654
  /(nokia) (t[12][01])/i
620
655
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
@@ -625,21 +660,19 @@
625
660
  // Google
626
661
  /(pixel (c|tablet))\b/i // Google Pixel C/Tablet
627
662
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [
628
- /droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i // Google Pixel
663
+ // Google Pixel
664
+ /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
629
665
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
666
+ /(google) (pixelbook( go)?)/i
667
+ ], [VENDOR, MODEL], [
630
668
 
631
669
  // Sony
632
- /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
670
+ /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
633
671
  ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
634
672
  /sony tablet [ps]/i,
635
673
  /\b(?:sony)?sgp\w+(?: bui|\))/i
636
674
  ], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [
637
675
 
638
- // OnePlus
639
- / (kb2005|in20[12]5|be20[12][59])\b/i,
640
- /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
641
- ], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
642
-
643
676
  // Amazon
644
677
  /(alexa)webm/i,
645
678
  /(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i, // Kindle Fire without Silk / Echo Show
@@ -710,25 +743,35 @@
710
743
  ], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [
711
744
 
712
745
  // Nothing
713
- /droid.+; (a(?:015|06[35]|142p?))/i
746
+ /droid.+; (a(in)?(0(15|59|6[35])|142)p?)/i
714
747
  ], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [
715
748
 
749
+ // Archos
750
+ /; (x67 5g|tikeasy \w+|ac[1789]\d\w+)( b|\))/i,
751
+ /archos ?(5|gamepad2?|([\w ]*[t1789]|hello) ?\d+[\w ]*)( b|\))/i
752
+ ], [MODEL, [VENDOR, 'Archos'], [TYPE, TABLET]], [
753
+ /archos ([\w ]+)( b|\))/i,
754
+ /; (ac[3-6]\d\w{2,8})( b|\))/i
755
+ ], [MODEL, [VENDOR, 'Archos'], [TYPE, MOBILE]], [
756
+
757
+ // HMD
758
+ /; (n159v)/i
759
+ ], [MODEL, [VENDOR, 'HMD'], [TYPE, MOBILE]], [
760
+
716
761
  // MIXED
717
762
  /(imo) (tab \w+)/i, // IMO
718
- /(infinix) (x1101b?)/i // Infinix XPad
763
+ /(infinix|tecno) (x1101b?|p904|dp(7c|8d|10a)( pro)?|p70[1-3]a?|p904|t1101)/i // Infinix XPad / Tecno
719
764
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
720
765
 
721
- /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|infinix|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
722
- // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Infinix/Tecno/Micromax/Advan
723
- /; (hmd|imo) ([\w ]+?)(?: bui|\))/i, // HMD/IMO
766
+ /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
767
+ // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Tecno/Micromax/Advan
768
+ /; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
724
769
  /(hp) ([\w ]+\w)/i, // HP iPAQ
725
770
  /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
726
- /(lenovo)[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i, // Lenovo
727
771
  /(oppo) ?([\w ]+) bui/i // OPPO
728
772
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
729
773
 
730
774
  /(kobo)\s(ereader|touch)/i, // Kobo
731
- /(archos) (gamepad2?)/i, // Archos
732
775
  /(hp).+(touchpad(?!.+tablet)|tablet)/i, // HP TouchPad
733
776
  /(kindle)\/([\w\.]+)/i // Kindle
734
777
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
@@ -756,7 +799,10 @@
756
799
  ], [VENDOR, [TYPE, SMARTTV]], [
757
800
  /hbbtv.+maple;(\d+)/i
758
801
  ], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [
759
- /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i // LG SmartTV
802
+ /(vizio)(?: |.+model\/)(\w+-\w+)/i, // Vizio
803
+ /tcast.+(lg)e?. ([-\w]+)/i // LG SmartTV
804
+ ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
805
+ /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i
760
806
  ], [[VENDOR, LG], [TYPE, SMARTTV]], [
761
807
  /(apple) ?tv/i // Apple TV
762
808
  ], [VENDOR, [MODEL, APPLE+' TV'], [TYPE, SMARTTV]], [
@@ -768,6 +814,8 @@
768
814
  ], [[MODEL, CHROMECAST+' Nest Hub'], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
769
815
  /crkey/i // Google Chromecast, Linux-based or unknown
770
816
  ], [[MODEL, CHROMECAST], [VENDOR, GOOGLE], [TYPE, SMARTTV]], [
817
+ /(portaltv)/i // Facebook Portal TV
818
+ ], [MODEL, [VENDOR, FACEBOOK], [TYPE, SMARTTV]], [
771
819
  /droid.+aft(\w+)( bui|\))/i // Fire TV
772
820
  ], [MODEL, [VENDOR, AMAZON], [TYPE, SMARTTV]], [
773
821
  /(shield \w+ tv)/i // Nvidia Shield TV
@@ -783,26 +831,27 @@
783
831
  ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
784
832
  /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
785
833
  /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
786
- ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [
834
+ ], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [
787
835
  // SmartTV from Unidentified Vendors
788
836
  /droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i
789
837
  ], [MODEL, [TYPE, SMARTTV]], [
790
- /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i
838
+ /\b(android tv|smart[- ]?tv|opera tv|tv; rv:|large screen[\w ]+safari)\b/i
791
839
  ], [[TYPE, SMARTTV]], [
792
840
 
793
841
  ///////////////////
794
842
  // CONSOLES
795
843
  ///////////////////
796
844
 
797
- /(ouya)/i, // Ouya
798
- /(nintendo) (\w+)/i // Nintendo
799
- ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
800
- /droid.+; (shield)( bui|\))/i // Nvidia Portable
801
- ], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
802
845
  /(playstation \w+)/i // Playstation
803
846
  ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
804
847
  /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
805
848
  ], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
849
+ /(ouya)/i, // Ouya
850
+ /(nintendo) (\w+)/i, // Nintendo
851
+ /(retroid) (pocket ([^\)]+))/i // Retroid Pocket
852
+ ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
853
+ /droid.+; (shield)( bui|\))/i // Nvidia Portable
854
+ ], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
806
855
 
807
856
  ///////////////////
808
857
  // WEARABLES
@@ -836,8 +885,10 @@
836
885
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
837
886
  /(pico) (4|neo3(?: link|pro)?)/i // Pico
838
887
  ], [VENDOR, MODEL, [TYPE, XR]], [
839
- /; (quest( \d| pro)?)/i // Oculus Quest
888
+ /(quest( \d| pro)?s?).+vr/i // Meta Quest
840
889
  ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
890
+ /mobile vr; rv.+firefox/i // Unidentifiable VR device using Firefox Reality / Wolvic
891
+ ], [[TYPE, XR]], [
841
892
 
842
893
  ///////////////////
843
894
  // EMBEDDED
@@ -849,7 +900,7 @@
849
900
  ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
850
901
  /(homepod).+mac os/i // Apple HomePod
851
902
  ], [MODEL, [VENDOR, APPLE], [TYPE, EMBEDDED]], [
852
- /windows iot/i
903
+ /windows iot/i // Unidentifiable embedded device using Windows IoT
853
904
  ], [[TYPE, EMBEDDED]], [
854
905
 
855
906
  ////////////////////
@@ -895,14 +946,17 @@
895
946
  os : [[
896
947
 
897
948
  // Windows
898
- /microsoft (windows) (vista|xp)/i // Windows (iTunes)
949
+ /(windows nt) (6\.[23]); arm/i // Windows RT
950
+ ], [[NAME, /N/, 'R'], [VERSION, strMapper, windowsVersionMap]], [
951
+ /(windows (?:phone|mobile|iot))(?: os)?[\/ ]?([\d\.]*( se)?)/i, // Windows IoT/Mobile/Phone
952
+ // Windows NT/3.1/95/98/ME/2000/XP/Vista/7/8/8.1/10/11
953
+ /(windows)[\/ ](1[01]|2000|3\.1|7|8(\.1)?|9[58]|me|server 20\d\d( r2)?|vista|xp)/i
954
+ ], [NAME, VERSION], [
955
+ /windows nt ?([\d\.\)]*)(?!.+xbox)/i,
956
+ /\bwin(?=3| ?9|n)(?:nt| 9x )?([\d\.;]*)/i
957
+ ], [[VERSION, /(;|\))/g, '', strMapper, windowsVersionMap], [NAME, WINDOWS]], [
958
+ /(windows ce)\/?([\d\.]*)/i // Windows CE
899
959
  ], [NAME, VERSION], [
900
- /(windows (?:phone(?: os)?|mobile|iot))[\/ ]?([\d\.\w ]*)/i // Windows Phone
901
- ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
902
- /windows nt 6\.2; (arm)/i, // Windows RT
903
- /windows[\/ ]([ntce\d\. ]+\w)(?!.+xbox)/i,
904
- /(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i
905
- ], [[VERSION, strMapper, windowsVersionMap], [NAME, WINDOWS]], [
906
960
 
907
961
  // iOS/macOS
908
962
  /[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
@@ -910,7 +964,7 @@
910
964
  /cfnetwork\/.+darwin/i
911
965
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
912
966
  /(mac os x) ?([\w\. ]*)/i,
913
- /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
967
+ /(macintosh|mac_powerpc\b)(?!.+(haiku|morphos))/i // Mac OS
914
968
  ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
915
969
 
916
970
  // Google Chromecast
@@ -926,12 +980,13 @@
926
980
  ], [VERSION, [NAME, CHROMECAST]], [
927
981
 
928
982
  // Mobile OSes
929
- /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
983
+ /droid ([\w\.]+)\b.+(android[- ]x86)/i // Android-x86
930
984
  ], [VERSION, NAME], [
931
985
  /(ubuntu) ([\w\.]+) like android/i // Ubuntu Touch
932
986
  ], [[NAME, /(.+)/, '$1 Touch'], VERSION], [
987
+ /(harmonyos)[\/ ]?([\d\.]*)/i, // HarmonyOS
933
988
  // Android/Blackberry/WebOS/QNX/Bada/RIM/KaiOS/Maemo/MeeGo/S40/Sailfish OS/OpenHarmony/Tizen
934
- /(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen|webos)\w*[-\/; ]?([\d\.]*)/i
989
+ /(android|bada|blackberry|kaios|maemo|meego|openharmony|qnx|rim tablet os|sailfish|series40|symbian|tizen)\w*[-\/\.; ]?([\d\.]*)/i
935
990
  ], [NAME, VERSION], [
936
991
  /\(bb(10);/i // BlackBerry 10
937
992
  ], [VERSION, [NAME, BLACKBERRY]], [
@@ -939,9 +994,12 @@
939
994
  ], [VERSION, [NAME, 'Symbian']], [
940
995
  /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS
941
996
  ], [VERSION, [NAME, FIREFOX+' OS']], [
942
- /web0s;.+rt(tv)/i,
943
- /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i // WebOS
997
+ /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i, // WebOS
998
+ /webos(?:[ \/]?|\.tv-20(?=2[2-9]))(\d[\d\.]*)/i
944
999
  ], [VERSION, [NAME, 'webOS']], [
1000
+ /web0s;.+?(?:chr[o0]me|safari)\/(\d+)/i
1001
+ // https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine
1002
+ ], [[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']], [
945
1003
  /watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
946
1004
  ], [VERSION, [NAME, 'watchOS']], [
947
1005
 
@@ -961,20 +1019,20 @@
961
1019
 
962
1020
  // Other
963
1021
  /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm
964
- /(mint)[\/\(\) ]?(\w*)/i, // Mint
965
- /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux
966
- /([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,
967
- // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire
968
- /(hurd|linux)(?: arm\w*| x86\w*| ?)([\w\.]*)/i, // Hurd/Linux
1022
+ /linux.+(mint)[\/\(\) ]?([\w\.]*)/i, // Mint
1023
+ /(mageia|vectorlinux|fuchsia|arcaos|arch(?= ?linux))[;l ]([\d\.]*)/i, // Mageia/VectorLinux/Fuchsia/ArcaOS/Arch
1024
+ /([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,
1025
+ // Ubuntu/Debian/SUSE/Gentoo/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire/Knoppix
1026
+ /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
1027
+ /\b(aix)[; ]([1-9\.]{0,4})/i, // AIX
1028
+ /(hurd|linux|morphos)(?: (?:arm|x86|ppc)\w*| ?)([\w\.]*)/i, // Hurd/Linux/MorphOS
969
1029
  /(gnu) ?([\w\.]*)/i, // GNU
970
1030
  /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly
971
- /(haiku) (\w+)/i // Haiku
1031
+ /(haiku) ?(r\d)?/i // Haiku
972
1032
  ], [NAME, VERSION], [
973
- /(sunos) ?([\w\.\d]*)/i // Solaris
1033
+ /(sunos) ?([\d\.]*)/i // Solaris
974
1034
  ], [[NAME, 'Solaris'], VERSION], [
975
- /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
976
- /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
977
- /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX/SerenityOS
1035
+ /\b(beos|os\/2|amigaos|openvms|hp-ux|serenityos)/i, // BeOS/OS2/AmigaOS/OpenVMS/HP-UX/SerenityOS
978
1036
  /(unix) ?([\w\.]*)/i // UNIX
979
1037
  ], [NAME, VERSION]
980
1038
  ]
@@ -1208,17 +1266,20 @@
1208
1266
  for (var i in brands) {
1209
1267
  var brandName = brands[i].brand || brands[i],
1210
1268
  brandVersion = brands[i].version;
1211
- if (this.itemType == UA_BROWSER && !/not.a.brand/i.test(brandName) && (!prevName || (/chrom/i.test(prevName) && brandName != CHROMIUM))) {
1212
- brandName = strMapper(brandName, {
1213
- 'Chrome' : 'Google Chrome',
1214
- 'Edge' : 'Microsoft Edge',
1215
- 'Chrome WebView' : 'Android WebView',
1216
- 'Chrome Headless' : 'HeadlessChrome'
1217
- });
1218
- this.set(NAME, brandName)
1219
- .set(VERSION, brandVersion)
1220
- .set(MAJOR, majorize(brandVersion));
1221
- prevName = brandName;
1269
+ if (this.itemType == UA_BROWSER &&
1270
+ !/not.a.brand/i.test(brandName) &&
1271
+ (!prevName ||
1272
+ (/Chrom/.test(prevName) && brandName != CHROMIUM) ||
1273
+ (prevName == EDGE && /WebView2/.test(brandName))
1274
+ )) {
1275
+ brandName = strMapper(brandName, browserHintsMap);
1276
+ prevName = this.get(NAME);
1277
+ if (!(prevName && !/Chrom/.test(prevName) && /Chrom/.test(brandName))) {
1278
+ this.set(NAME, brandName)
1279
+ .set(VERSION, brandVersion)
1280
+ .set(MAJOR, majorize(brandVersion));
1281
+ }
1282
+ prevName = brandName;
1222
1283
  }
1223
1284
  if (this.itemType == UA_ENGINE && brandName == CHROMIUM) {
1224
1285
  this.set(VERSION, brandVersion);