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