ua-parser-js 2.0.3 → 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,5 +1,5 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////
2
- /* UAParser.js v2.0.3
2
+ /* UAParser.js v2.0.4
3
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.
@@ -19,7 +19,7 @@
19
19
  // Constants
20
20
  /////////////
21
21
 
22
- var LIBVERSION = '2.0.3',
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
@@ -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,16 +602,22 @@
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
- // BLU Vivo Series
589
- /(vivo (5r?|6|8l?|go|one|s|x[il]?[2-4]?)[\w\+ ]*)(?: bui|\))/i
590
- ], [MODEL, [VENDOR, 'BLU'], [TYPE, MOBILE]], [
591
621
  // Vivo
592
622
  /; vivo (\w+)(?: bui|\))/i,
593
623
  /\b(v[12]\d{3}\w?[at])(?: bui|;)/i
@@ -597,10 +627,17 @@
597
627
  /\b(rmx[1-3]\d{3})(?: bui|;|\))/i
598
628
  ], [MODEL, [VENDOR, 'Realme'], [TYPE, MOBILE]], [
599
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
+
600
637
  // Motorola
601
638
  /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i,
602
- /\bmot(?:orola)?[- ](\w*)/i,
603
- /((?: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
604
641
  ], [MODEL, [VENDOR, MOTOROLA], [TYPE, MOBILE]], [
605
642
  /\b(mz60\d|xoom[2 ]{0,2}) build\//i
606
643
  ], [MODEL, [VENDOR, MOTOROLA], [TYPE, TABLET]], [
@@ -609,15 +646,10 @@
609
646
  /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i
610
647
  ], [MODEL, [VENDOR, LG], [TYPE, TABLET]], [
611
648
  /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i,
612
- /\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch))(\w+)/i,
649
+ /\blg[-e;\/ ]+(?!.*(?:browser|netcast|android tv|watch|webos))(\w+)/i,
613
650
  /\blg-?([\d\w]+) bui/i
614
651
  ], [MODEL, [VENDOR, LG], [TYPE, MOBILE]], [
615
652
 
616
- // Lenovo
617
- /(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,
618
- /lenovo ?(b[68]0[08]0-?[hf]?|tab(?:[\w- ]+?)|tb[\w-]{6,7})( bui|;|\)|\/)/i
619
- ], [MODEL, [VENDOR, LENOVO], [TYPE, TABLET]], [
620
-
621
653
  // Nokia
622
654
  /(nokia) (t[12][01])/i
623
655
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
@@ -628,21 +660,19 @@
628
660
  // Google
629
661
  /(pixel (c|tablet))\b/i // Google Pixel C/Tablet
630
662
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, TABLET]], [
631
- /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
632
665
  ], [MODEL, [VENDOR, GOOGLE], [TYPE, MOBILE]], [
666
+ /(google) (pixelbook( go)?)/i
667
+ ], [VENDOR, MODEL], [
633
668
 
634
669
  // Sony
635
- /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
636
671
  ], [MODEL, [VENDOR, SONY], [TYPE, MOBILE]], [
637
672
  /sony tablet [ps]/i,
638
673
  /\b(?:sony)?sgp\w+(?: bui|\))/i
639
674
  ], [[MODEL, 'Xperia Tablet'], [VENDOR, SONY], [TYPE, TABLET]], [
640
675
 
641
- // OnePlus
642
- / (kb2005|in20[12]5|be20[12][59])\b/i,
643
- /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i
644
- ], [MODEL, [VENDOR, ONEPLUS], [TYPE, MOBILE]], [
645
-
646
676
  // Amazon
647
677
  /(alexa)webm/i,
648
678
  /(kf[a-z]{2}wi|aeo(?!bc)\w\w)( bui|\))/i, // Kindle Fire without Silk / Echo Show
@@ -713,7 +743,7 @@
713
743
  ], [MODEL, [VENDOR, 'Smartfren'], [TYPE, MOBILE]], [
714
744
 
715
745
  // Nothing
716
- /droid.+; (a(?:015|06[35]|142p?))/i
746
+ /droid.+; (a(in)?(0(15|59|6[35])|142)p?)/i
717
747
  ], [MODEL, [VENDOR, 'Nothing'], [TYPE, MOBILE]], [
718
748
 
719
749
  // Archos
@@ -724,17 +754,20 @@
724
754
  /; (ac[3-6]\d\w{2,8})( b|\))/i
725
755
  ], [MODEL, [VENDOR, 'Archos'], [TYPE, MOBILE]], [
726
756
 
757
+ // HMD
758
+ /; (n159v)/i
759
+ ], [MODEL, [VENDOR, 'HMD'], [TYPE, MOBILE]], [
760
+
727
761
  // MIXED
728
762
  /(imo) (tab \w+)/i, // IMO
729
- /(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
730
764
  ], [VENDOR, MODEL, [TYPE, TABLET]], [
731
765
 
732
- /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus(?! zenw)|dell|jolla|meizu|motorola|polytron|infinix|tecno|micromax|advan)[-_ ]?([-\w]*)/i,
733
- // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron/Infinix/Tecno/Micromax/Advan
734
- /; (blu|hmd|imo|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/TCL
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
735
769
  /(hp) ([\w ]+\w)/i, // HP iPAQ
736
770
  /(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
737
- /(lenovo)[-_ ]?([-\w ]+?)(?: bui|\)|\/)/i, // Lenovo
738
771
  /(oppo) ?([\w ]+) bui/i // OPPO
739
772
  ], [VENDOR, MODEL, [TYPE, MOBILE]], [
740
773
 
@@ -766,6 +799,7 @@
766
799
  ], [VENDOR, [TYPE, SMARTTV]], [
767
800
  /hbbtv.+maple;(\d+)/i
768
801
  ], [[MODEL, /^/, 'SmartTV'], [VENDOR, SAMSUNG], [TYPE, SMARTTV]], [
802
+ /(vizio)(?: |.+model\/)(\w+-\w+)/i, // Vizio
769
803
  /tcast.+(lg)e?. ([-\w]+)/i // LG SmartTV
770
804
  ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
771
805
  /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i
@@ -797,26 +831,27 @@
797
831
  ], [VENDOR, MODEL, [TYPE, SMARTTV]], [
798
832
  /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
799
833
  /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
800
- ], [[VENDOR, trim], [MODEL, trim], [TYPE, SMARTTV]], [
834
+ ], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [
801
835
  // SmartTV from Unidentified Vendors
802
836
  /droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i
803
837
  ], [MODEL, [TYPE, SMARTTV]], [
804
- /\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
805
839
  ], [[TYPE, SMARTTV]], [
806
840
 
807
841
  ///////////////////
808
842
  // CONSOLES
809
843
  ///////////////////
810
844
 
811
- /(ouya)/i, // Ouya
812
- /(nintendo) (\w+)/i // Nintendo
813
- ], [VENDOR, MODEL, [TYPE, CONSOLE]], [
814
- /droid.+; (shield)( bui|\))/i // Nvidia Portable
815
- ], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
816
845
  /(playstation \w+)/i // Playstation
817
846
  ], [MODEL, [VENDOR, SONY], [TYPE, CONSOLE]], [
818
847
  /\b(xbox(?: one)?(?!; xbox))[\); ]/i // Microsoft Xbox
819
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]], [
820
855
 
821
856
  ///////////////////
822
857
  // WEARABLES
@@ -852,6 +887,8 @@
852
887
  ], [VENDOR, MODEL, [TYPE, XR]], [
853
888
  /(quest( \d| pro)?s?).+vr/i // Meta Quest
854
889
  ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
890
+ /mobile vr; rv.+firefox/i // Unidentifiable VR device using Firefox Reality / Wolvic
891
+ ], [[TYPE, XR]], [
855
892
 
856
893
  ///////////////////
857
894
  // EMBEDDED
@@ -863,7 +900,7 @@
863
900
  ], [MODEL, [VENDOR, AMAZON], [TYPE, EMBEDDED]], [
864
901
  /(homepod).+mac os/i // Apple HomePod
865
902
  ], [MODEL, [VENDOR, APPLE], [TYPE, EMBEDDED]], [
866
- /windows iot/i
903
+ /windows iot/i // Unidentifiable embedded device using Windows IoT
867
904
  ], [[TYPE, EMBEDDED]], [
868
905
 
869
906
  ////////////////////
@@ -909,14 +946,17 @@
909
946
  os : [[
910
947
 
911
948
  // Windows
912
- /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
913
959
  ], [NAME, VERSION], [
914
- /(windows (?:phone(?: os)?|mobile|iot))[\/ ]?([\d\.\w ]*)/i // Windows Phone
915
- ], [NAME, [VERSION, strMapper, windowsVersionMap]], [
916
- /windows nt 6\.2; (arm)/i, // Windows RT
917
- /windows[\/ ]([ntce\d\. ]+\w)(?!.+xbox)/i,
918
- /(?:win(?=3|9|n)|win 9x )([nt\d\.]+)/i
919
- ], [[VERSION, strMapper, windowsVersionMap], [NAME, WINDOWS]], [
920
960
 
921
961
  // iOS/macOS
922
962
  /[adehimnop]{4,7}\b(?:.*os ([\w]+) like mac|; opera)/i, // iOS
@@ -924,7 +964,7 @@
924
964
  /cfnetwork\/.+darwin/i
925
965
  ], [[VERSION, /_/g, '.'], [NAME, 'iOS']], [
926
966
  /(mac os x) ?([\w\. ]*)/i,
927
- /(macintosh|mac_powerpc\b)(?!.+haiku)/i // Mac OS
967
+ /(macintosh|mac_powerpc\b)(?!.+(haiku|morphos))/i // Mac OS
928
968
  ], [[NAME, 'macOS'], [VERSION, /_/g, '.']], [
929
969
 
930
970
  // Google Chromecast
@@ -940,12 +980,13 @@
940
980
  ], [VERSION, [NAME, CHROMECAST]], [
941
981
 
942
982
  // Mobile OSes
943
- /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i // Android-x86/HarmonyOS
983
+ /droid ([\w\.]+)\b.+(android[- ]x86)/i // Android-x86
944
984
  ], [VERSION, NAME], [
945
985
  /(ubuntu) ([\w\.]+) like android/i // Ubuntu Touch
946
986
  ], [[NAME, /(.+)/, '$1 Touch'], VERSION], [
987
+ /(harmonyos)[\/ ]?([\d\.]*)/i, // HarmonyOS
947
988
  // Android/Blackberry/WebOS/QNX/Bada/RIM/KaiOS/Maemo/MeeGo/S40/Sailfish OS/OpenHarmony/Tizen
948
- /(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
949
990
  ], [NAME, VERSION], [
950
991
  /\(bb(10);/i // BlackBerry 10
951
992
  ], [VERSION, [NAME, BLACKBERRY]], [
@@ -953,9 +994,12 @@
953
994
  ], [VERSION, [NAME, 'Symbian']], [
954
995
  /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i // Firefox OS
955
996
  ], [VERSION, [NAME, FIREFOX+' OS']], [
956
- /web0s;.+rt(tv)/i,
957
- /\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
958
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']], [
959
1003
  /watch(?: ?os[,\/]|\d,\d\/)([\d\.]+)/i // watchOS
960
1004
  ], [VERSION, [NAME, 'watchOS']], [
961
1005
 
@@ -975,20 +1019,20 @@
975
1019
 
976
1020
  // Other
977
1021
  /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, // Joli/Palm
978
- /(mint)[\/\(\) ]?(\w*)/i, // Mint
979
- /(mageia|vectorlinux)[; ]/i, // Mageia/VectorLinux
980
- /([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,
981
- // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire
982
- /(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
983
1029
  /(gnu) ?([\w\.]*)/i, // GNU
984
1030
  /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly
985
- /(haiku) (\w+)/i // Haiku
1031
+ /(haiku) ?(r\d)?/i // Haiku
986
1032
  ], [NAME, VERSION], [
987
- /(sunos) ?([\w\.\d]*)/i // Solaris
1033
+ /(sunos) ?([\d\.]*)/i // Solaris
988
1034
  ], [[NAME, 'Solaris'], VERSION], [
989
- /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, // Solaris
990
- /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, // AIX
991
- /\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
992
1036
  /(unix) ?([\w\.]*)/i // UNIX
993
1037
  ], [NAME, VERSION]
994
1038
  ]
@@ -1222,21 +1266,20 @@
1222
1266
  for (var i in brands) {
1223
1267
  var brandName = brands[i].brand || brands[i],
1224
1268
  brandVersion = brands[i].version;
1225
- if (this.itemType == UA_BROWSER && !/not.a.brand/i.test(brandName) && (!prevName || (/chrom/i.test(prevName) && brandName != CHROMIUM))) {
1226
- brandName = strMapper(brandName, {
1227
- 'Chrome' : 'Google Chrome',
1228
- 'Edge' : 'Microsoft Edge',
1229
- 'Chrome WebView' : 'Android WebView',
1230
- 'Chrome Headless' : 'HeadlessChrome',
1231
- 'Huawei Browser' : 'HuaweiBrowser',
1232
- 'MIUI Browser' : 'Miui Browser',
1233
- 'Opera Mobi' : 'OperaMobile',
1234
- 'Yandex' : 'YaBrowser'
1235
- });
1236
- this.set(NAME, brandName)
1237
- .set(VERSION, brandVersion)
1238
- .set(MAJOR, majorize(brandVersion));
1239
- 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;
1240
1283
  }
1241
1284
  if (this.itemType == UA_ENGINE && brandName == CHROMIUM) {
1242
1285
  this.set(VERSION, brandVersion);