user_agent_parser 2.1.1 → 2.2.0

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.

Potentially problematic release.


This version of user_agent_parser might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e20682e690e1e3552bc54b1ef9849ab8febc3ec
4
- data.tar.gz: 8f7578787fc31f82e35909d34c86b1b00594b0b6
3
+ metadata.gz: 3e6c42fb7a24030be52fa5c096b8af27e362bb02
4
+ data.tar.gz: 60cfeb6d90444739f7f81f0e035704e23b5597df
5
5
  SHA512:
6
- metadata.gz: 488d4f2b60187907f65ad244786c6babfef042fa16d5a70292a29aac70fda3cbbf7dead070d2c30123b9a81c46c3385e4347994692342d3b127fb5baba01d6dd
7
- data.tar.gz: a8213bbf5f3b4fb36665d36b7c401c6ec40acfcacc0b52340bcb36a402b038ea5c658837d449c2cd04ad04142334f080bd2479ae4ae5c7b4fd67f54e49c46b0b
6
+ metadata.gz: 9fe9aa53552e5fb33d04bdc412a4cfb684ef5e04cb75f0d3747a8036ae804891072f1114dba9729d243d7bb138e610f954ee108dc4d1dda025ac1155bf4e2445
7
+ data.tar.gz: 06ba11a996ca450f7db3a5fc5175c76d703e3cd2496013c0d09bc34a1f63cf8a145ee2a1fa1ee48b37152074ab6c12b98c0e4f62c9e305af59432f69d7fd10b3
data/Readme.md CHANGED
@@ -2,9 +2,13 @@
2
2
 
3
3
  UserAgentParser is a simple, comprehensive Ruby gem for parsing user agent strings. It uses [BrowserScope](http://www.browserscope.org/)'s [parsing patterns](https://github.com/tobie/ua-parser).
4
4
 
5
- ## Requirements
5
+ ## Supported Rubies
6
6
 
7
- * Ruby >= 1.8.7
7
+ * Ruby 2.1
8
+ * Ruby 2.0
9
+ * Ruby 1.9.3
10
+ * Ruby 1.9.2
11
+ * JRuby
8
12
 
9
13
  ## Installation
10
14
 
@@ -21,7 +25,7 @@ user_agent = UserAgentParser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows N
21
25
  => #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
22
26
  user_agent.to_s
23
27
  => "IE 9.0"
24
- user_agent.name
28
+ user_agent.family
25
29
  => "IE"
26
30
  user_agent.version.to_s
27
31
  => "9.0"
@@ -74,6 +78,17 @@ or when instantiating a `UserAgentParser::Parser`:
74
78
  UserAgentParser::Parser.new(patterns_path: '/some/path/to/regexes.yaml').parse(ua_string)
75
79
  ```
76
80
 
81
+ ## Binary: user_agent_parser
82
+
83
+ There is a binary called `user_agent_parser` that will read from
84
+ standard input, parse each line and print the result, for example:
85
+
86
+ ```ruby
87
+ $ cat SOME-FILE.json | user_agent_parser --format '%n %M' | distribution
88
+ ```
89
+
90
+ See `user_agent_parser -h` for more information.
91
+
77
92
  ## Contributing
78
93
 
79
94
  1. Fork
@@ -94,6 +109,7 @@ All accepted pull requests will earn you commit and release rights.
94
109
  * Some new feature
95
110
  * Some new bug fix
96
111
  3. `rake release`
112
+ 4. Create a [new Github release](https://github.com/toolmantim/user_agent_parser/releases/new)
97
113
 
98
114
  ## License
99
115
 
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require 'user_agent_parser'
6
+ require 'user_agent_parser/cli'
7
+
8
+ options = {}
9
+
10
+ optparse = OptionParser.new do|opts|
11
+ opts.on('--family', 'Print family only') do
12
+ options[:family] = true
13
+ end
14
+
15
+ opts.on('--name', 'Print name (alias for family) only') do
16
+ options[:family] = true
17
+ end
18
+
19
+ opts.on('--version', 'Print version only') do
20
+ options[:version] = true
21
+ end
22
+
23
+ opts.on('--major', 'Print major version only') do
24
+ options[:major] = true
25
+ end
26
+
27
+ opts.on('--minor', 'Print minor version only') do
28
+ options[:minor] = true
29
+ end
30
+
31
+ opts.on('--os', 'Print operating system only') do
32
+ options[:os] = true
33
+ end
34
+
35
+ opts.on('--format format',
36
+ 'Print output in specified format. The available formatters are:',
37
+ ' - %f: family',
38
+ ' - %n: name (alias for family)',
39
+ ' - %v: version',
40
+ ' - %M: major version',
41
+ ' - %m: minor version',
42
+ ' - %o: operating system'
43
+ ) do |format|
44
+ options[:format] = format
45
+ end
46
+
47
+ opts.on('-h', '--help', 'Display this screen') do
48
+ puts opts
49
+ exit
50
+ end
51
+ end
52
+
53
+ optparse.parse!
54
+
55
+ parser = UserAgentParser::Parser.new
56
+
57
+ ARGF.each do |line|
58
+ puts UserAgentParser::Cli.new(parser.parse(line), options).run!
59
+ end
@@ -0,0 +1,58 @@
1
+ module UserAgentParser
2
+ class Cli
3
+ def initialize(user_agent, options = {})
4
+ @user_agent = user_agent
5
+ @options = options
6
+ end
7
+
8
+ def run!
9
+ if @options[:family]
10
+ @user_agent.family
11
+ elsif @options[:name]
12
+ @user_agent.name
13
+ elsif @options[:version]
14
+ with_version do |version|
15
+ version.to_s
16
+ end
17
+ elsif @options[:major]
18
+ major
19
+ elsif @options[:minor]
20
+ minor
21
+ elsif @options[:os]
22
+ @user_agent.os.to_s
23
+ elsif format = @options[:format]
24
+ format.
25
+ gsub('%f', @user_agent.family).
26
+ gsub('%n', @user_agent.name).
27
+ gsub('%v', version.to_s).
28
+ gsub('%M', major.to_s).
29
+ gsub('%m', minor.to_s).
30
+ gsub('%o', @user_agent.os.to_s)
31
+ else
32
+ @user_agent.to_s
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def major
39
+ with_version do |version|
40
+ version.major
41
+ end
42
+ end
43
+
44
+ def minor
45
+ with_version do |version|
46
+ version.minor
47
+ end
48
+ end
49
+
50
+ def version
51
+ @version ||= @user_agent.version
52
+ end
53
+
54
+ def with_version(&block)
55
+ block.call(version) if version
56
+ end
57
+ end
58
+ end
@@ -1,13 +1,15 @@
1
1
  module UserAgentParser
2
2
  class Device
3
- attr_reader :name
3
+ attr_reader :family
4
4
 
5
- def initialize(name = nil)
6
- @name = name || 'Other'
5
+ alias_method :name, :family
6
+
7
+ def initialize(family = nil)
8
+ @family = family || 'Other'
7
9
  end
8
10
 
9
11
  def to_s
10
- name
12
+ family
11
13
  end
12
14
 
13
15
  def inspect
@@ -15,7 +17,7 @@ module UserAgentParser
15
17
  end
16
18
 
17
19
  def eql?(other)
18
- self.class.eql?(other.class) && name == other.name
20
+ self.class.eql?(other.class) && family == other.family
19
21
  end
20
22
 
21
23
  alias_method :==, :eql?
@@ -1,14 +1,16 @@
1
1
  module UserAgentParser
2
2
  class OperatingSystem
3
- attr_reader :name, :version
3
+ attr_reader :family, :version
4
4
 
5
- def initialize(name = 'Other', version = nil)
6
- @name = name
5
+ alias_method :name, :family
6
+
7
+ def initialize(family = 'Other', version = nil)
8
+ @family = family
7
9
  @version = version
8
10
  end
9
11
 
10
12
  def to_s
11
- string = name
13
+ string = family
12
14
  unless version.nil?
13
15
  string += " #{version}"
14
16
  end
@@ -21,7 +23,7 @@ module UserAgentParser
21
23
 
22
24
  def eql?(other)
23
25
  self.class.eql?(other.class) &&
24
- name == other.name &&
26
+ family == other.family &&
25
27
  version == other.version
26
28
  end
27
29
 
@@ -1,7 +1,7 @@
1
1
  require 'yaml'
2
2
 
3
3
  module UserAgentParser
4
-
4
+
5
5
  class Parser
6
6
  attr_reader :patterns_path
7
7
 
@@ -71,10 +71,10 @@ module UserAgentParser
71
71
  end
72
72
 
73
73
  def user_agent_from_pattern_match(pattern, match, os = nil, device = nil)
74
- name, v1, v2, v3, v4 = match[1], match[2], match[3], match[4], match[5]
74
+ family, v1, v2, v3, v4 = match[1], match[2], match[3], match[4], match[5]
75
75
 
76
76
  if pattern["family_replacement"]
77
- name = pattern["family_replacement"].sub('$1', name || '')
77
+ family = pattern["family_replacement"].sub('$1', family || '')
78
78
  end
79
79
 
80
80
  if pattern["v1_replacement"]
@@ -95,7 +95,7 @@ module UserAgentParser
95
95
 
96
96
  version = version_from_segments(v1, v2, v3, v4)
97
97
 
98
- UserAgent.new(name, version, os, device)
98
+ UserAgent.new(family, version, os, device)
99
99
  end
100
100
 
101
101
  def os_from_pattern_match(pattern, match)
@@ -137,8 +137,8 @@ module UserAgentParser
137
137
  end
138
138
 
139
139
  def version_from_segments(*segments)
140
- version_string = segments.compact.join(".")
141
- version_string.empty? ? nil : Version.new(version_string)
140
+ segments = segments.compact
141
+ segments.empty? ? nil : Version.new(*segments)
142
142
  end
143
143
  end
144
144
  end
@@ -1,19 +1,18 @@
1
1
  module UserAgentParser
2
2
  class UserAgent
3
- attr_reader :name, :version, :os, :device
3
+ attr_reader :family, :version, :os, :device
4
4
 
5
- # For backwards compatibility with older versions of this gem.
6
- alias_method :family, :name
5
+ alias_method :name, :family
7
6
 
8
- def initialize(name = nil, version = nil, os = nil, device = nil)
9
- @name = name || 'Other'
7
+ def initialize(family = nil, version = nil, os = nil, device = nil)
8
+ @family = family || 'Other'
10
9
  @version = version
11
10
  @os = os
12
11
  @device = device
13
12
  end
14
13
 
15
14
  def to_s
16
- string = name
15
+ string = family
17
16
  string += " #{version}" if version
18
17
  string
19
18
  end
@@ -27,7 +26,7 @@ module UserAgentParser
27
26
 
28
27
  def eql?(other)
29
28
  self.class.eql?(other.class) &&
30
- name == other.name &&
29
+ family == other.family &&
31
30
  version == other.version &&
32
31
  os == other.os
33
32
  end
@@ -1,15 +1,20 @@
1
1
  module UserAgentParser
2
2
  class Version
3
3
 
4
- # Private: Regex used to split version string into major, minor, patch,
5
- # and patch_minor.
4
+ # Private: Regex used to split string version string into major, minor,
5
+ # patch, and patch_minor.
6
6
  SEGMENTS_REGEX = /\d+\-\d+|\d+[a-zA-Z]+$|\d+|[A-Za-z][0-9A-Za-z-]*$/
7
7
 
8
8
  attr_reader :version
9
9
  alias :to_s :version
10
10
 
11
- def initialize(version)
12
- @version = version.to_s.strip
11
+ def initialize(*args)
12
+ if args.length == 1 && args.first.is_a?(String)
13
+ @version = args.first.to_s.strip
14
+ else
15
+ @segments = args.map(&:to_s).map(&:strip)
16
+ @version = segments.join(".")
17
+ end
13
18
  end
14
19
 
15
20
  def major
@@ -6,8 +6,8 @@ user_agent_parsers:
6
6
  # See os_parsers if you want to target a specific TV
7
7
  - regex: '(HbbTV)/(\d+)\.(\d+)\.(\d+) \('
8
8
 
9
- # must go before Firefox to catch SeaMonkey/Camino
10
- - regex: '(SeaMonkey|Camino)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)'
9
+ # must go before Firefox to catch Chimera/SeaMonkey/Camino
10
+ - regex: '(Chimera|SeaMonkey|Camino)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)?'
11
11
 
12
12
  # Firefox
13
13
  - regex: '(Pale[Mm]oon)/(\d+)\.(\d+)\.?(\d+)?'
@@ -49,7 +49,7 @@ user_agent_parsers:
49
49
  - regex: '(Navigator)/(\d+)\.(\d+)([ab]\d+)'
50
50
  family_replacement: 'Netscape'
51
51
 
52
- - regex: '(Netscape6)/(\d+)\.(\d+)\.(\d+)'
52
+ - regex: '(Netscape6)/(\d+)\.(\d+)\.?([ab]?\d+)?'
53
53
  family_replacement: 'Netscape'
54
54
 
55
55
  - regex: '(MyIBrow)/(\d+)\.(\d+)'
@@ -60,10 +60,13 @@ user_agent_parsers:
60
60
  - regex: '(Opera Tablet).*Version/(\d+)\.(\d+)(?:\.(\d+))?'
61
61
  - regex: '(Opera)/.+Opera Mobi.+Version/(\d+)\.(\d+)'
62
62
  family_replacement: 'Opera Mobile'
63
+ - regex: '(Opera)/(\d+)\.(\d+).+Opera Mobi'
64
+ family_replacement: 'Opera Mobile'
65
+ - regex: 'Opera Mobi.+(Opera)(?:/|\s+)(\d+)\.(\d+)'
66
+ family_replacement: 'Opera Mobile'
63
67
  - regex: 'Opera Mobi'
64
68
  family_replacement: 'Opera Mobile'
65
- - regex: '(Opera Mini)/(\d+)\.(\d+)'
66
- - regex: '(Opera Mini)/att/(\d+)\.(\d+)'
69
+ - regex: '(Opera Mini)(?:/att)?/(\d+)\.(\d+)'
67
70
  - regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+))?'
68
71
 
69
72
  # Opera 14 for Android uses a WebKit render engine.
@@ -82,13 +85,13 @@ user_agent_parsers:
82
85
  # http://luakit.org/projects/luakit/
83
86
  - regex: '(luakit)'
84
87
  family_replacement: 'LuaKit'
85
-
88
+
86
89
  # Snowshoe
87
90
  - regex: '(Snowshoe)/(\d+)\.(\d+).(\d+)'
88
91
 
89
92
  # Lightning (for Thunderbird)
90
93
  # http://www.mozilla.org/projects/calendar/lightning/
91
- - regex: '(Lightning)/(\d+)\.(\d+)([ab]?\d+[a-z]*)'
94
+ - regex: '(Lightning)/(\d+)\.(\d+)\.?((?:[ab]?\d+[a-z]*)|(?:\d*))'
92
95
 
93
96
  # Swiftfox
94
97
  - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+(?:pre)?) \(Swiftfox\)'
@@ -123,6 +126,28 @@ user_agent_parsers:
123
126
 
124
127
  - regex: '(Minimo)'
125
128
 
129
+ - regex: 'PLAYSTATION 3.+WebKit'
130
+ family_replacement: 'NetFront NX'
131
+ - regex: 'PLAYSTATION 3'
132
+ family_replacement: 'NetFront'
133
+ - regex: '(PlayStation Portable)'
134
+ family_replacement: 'NetFront'
135
+ - regex: '(PlayStation Vita)'
136
+ family_replacement: 'NetFront NX'
137
+
138
+ - regex: 'AppleWebKit.+ (NX)/(\d+)\.(\d+)\.(\d+)'
139
+ family_replacement: 'NetFront NX'
140
+ - regex: '(Nintendo 3DS)'
141
+ family_replacement: 'NetFront NX'
142
+
143
+ # Amazon Silk, should go before Safari and Chrome Mobile
144
+ - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
145
+ family_replacement: 'Amazon Silk'
146
+
147
+
148
+ # @ref: http://www.puffinbrowser.com
149
+ - regex: '(Puffin)/(\d+)\.(\d+)(?:\.(\d+))?'
150
+
126
151
  # Chrome Mobile
127
152
  - regex: '(CrMo)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
128
153
  family_replacement: 'Chrome Mobile'
@@ -156,6 +181,14 @@ user_agent_parsers:
156
181
  - regex: '(FlyFlow)/(\d+)\.(\d+)'
157
182
  family_replacement: 'Baidu Explorer'
158
183
 
184
+ # QQ Browsers
185
+ - regex: '(MQQBrowser/Mini)(?:(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
186
+ family_replacement: 'QQ Browser Mini'
187
+ - regex: '(MQQBrowser)(?:/(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
188
+ family_replacement: 'QQ Browser Mobile'
189
+ - regex: '(QQBrowser)(?:/(\d+)(?:\.(\d+)\.(\d+)(?:\.(\d+))?)?)?'
190
+ family_replacement: 'QQ Browser'
191
+
159
192
  # Pingdom
160
193
  - regex: '(Pingdom.com_bot_version_)(\d+)\.(\d+)'
161
194
  family_replacement: 'PingdomBot'
@@ -164,10 +197,18 @@ user_agent_parsers:
164
197
  - regex: '(facebookexternalhit)/(\d+)\.(\d+)'
165
198
  family_replacement: 'FacebookBot'
166
199
 
200
+ # LinkedIn
201
+ - regex: '(LinkedInBot)/(\d+)\.(\d+)'
202
+ family_replacement: 'LinkedInBot'
203
+
167
204
  # Twitterbot
168
205
  - regex: '(Twitterbot)/(\d+)\.(\d+)'
169
206
  family_replacement: 'TwitterBot'
170
207
 
208
+ # Google Plus
209
+ - regex: 'Google.*/\+/web/snippet'
210
+ family_replacement: 'GooglePlusBot'
211
+
171
212
  # Rackspace Monitoring
172
213
  - regex: '(Rackspace Monitoring)/(\d+)\.(\d+)'
173
214
  family_replacement: 'RackspaceBot'
@@ -191,25 +232,63 @@ user_agent_parsers:
191
232
  #### MAIN CASES - this catches > 50% of all browsers ####
192
233
 
193
234
  # Browser/major_version.minor_version.beta_version
194
- - regex: '(AdobeAIR|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Flock|Netscape|Lunascape|WebPilot|Vodafone|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave)/(\d+)\.(\d+)\.(\d+)'
235
+ - regex: '(AdobeAIR|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Epiphany|Shiira|Sunrise|Flock|Netscape|Lunascape|WebPilot|NetFront|Netfront|Konqueror|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|Opera Mini|iCab|NetNewsWire|ThunderBrowse|Iris|UP\.Browser|Bunjalloo|Google Earth|Raven for Mac|Openwave)/(\d+)\.(\d+)\.(\d+)'
236
+
237
+ # Outlook 2007
238
+ - regex: 'MSOffice 12'
239
+ family_replacement: 'Outlook'
240
+ v1_replacement: '2007'
241
+
242
+ # Outlook 2010
243
+ - regex: 'MSOffice 14'
244
+ family_replacement: 'Outlook'
245
+ v1_replacement: '2010'
246
+
247
+ # Outlook 2013
248
+ - regex: 'Microsoft Outlook 15\.\d+\.\d+'
249
+ family_replacement: 'Outlook'
250
+ v1_replacement: '2013'
251
+
252
+ # Apple Air Mail
253
+ - regex: '(Airmail) (\d+)\.(\d+)(?:\.(\d+))?'
254
+
255
+ # Thunderbird
256
+ - regex: '(Thunderbird)/(\d+)\.(\d+)\.(\d+(?:pre)?)'
257
+ family_replacement: 'Thunderbird'
195
258
 
196
259
  # Chrome/Chromium/major_version.minor_version.beta_version
197
260
  - regex: '(Chromium|Chrome)/(\d+)\.(\d+)\.(\d+)'
198
261
 
262
+ # Dolphin Browser
263
+ # @ref: http://www.dolphin.com
264
+ - regex: '\b(Dolphin)(?: |HDCN/|/INT\-)(\d+)\.(\d+)\.?(\d+)?'
265
+
199
266
  # Browser/major_version.minor_version
200
- - regex: '(Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|Vodafone|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser)/(\d+)\.(\d+)'
267
+ - regex: '(bingbot|Bolt|Jasmine|IceCat|Skyfire|Midori|Maxthon|Lynx|Arora|IBrowse|Dillo|Camino|Shiira|Fennec|Phoenix|Chrome|Flock|Netscape|Lunascape|Epiphany|WebPilot|Opera Mini|Opera|NetFront|Netfront|Konqueror|Googlebot|SeaMonkey|Kazehakase|Vienna|Iceape|Iceweasel|IceWeasel|Iron|K-Meleon|Sleipnir|Galeon|GranParadiso|iCab|NetNewsWire|Space Bison|Stainless|Orca|Dolfin|BOLT|Minimo|Tizen Browser|Polaris|Abrowser|Planetweb|ICE Browser|mDolphin)/(\d+)\.(\d+)\.?(\d+)?'
201
268
 
202
269
  # Chrome/Chromium/major_version.minor_version
203
270
  - regex: '(Chromium|Chrome)/(\d+)\.(\d+)'
204
271
 
272
+ ##########
273
+ # IE Mobile needs to happen before Android to catch cases such as:
274
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920)...
275
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; ANZ821)...
276
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Orange)...
277
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Vodafone)...
278
+ ##########
279
+
280
+ # IE Mobile
281
+ - regex: '(IEMobile)[ /](\d+)\.(\d+)'
282
+ family_replacement: 'IE Mobile'
283
+
205
284
  # Browser major_version.minor_version.beta_version (space instead of slash)
206
285
  - regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)'
207
286
  # Browser major_version.minor_version (space instead of slash)
208
287
  - regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris) (\d+)\.(\d+)\.?(\d+)?'
209
-
288
+
210
289
  # Kindle WebKit
211
290
  - regex: '(Kindle)/(\d+)\.(\d+)'
212
-
291
+
213
292
  # weird android UAs
214
293
  - regex: '(Android) Donut'
215
294
  v1_replacement: '1'
@@ -230,18 +309,11 @@ user_agent_parsers:
230
309
  - regex: '(Android) Honeycomb'
231
310
  v1_replacement: '3'
232
311
 
233
- # IE Mobile
234
- - regex: '(IEMobile)[ /](\d+)\.(\d+)'
235
- family_replacement: 'IE Mobile'
236
312
  # desktop mode
237
313
  # http://www.anandtech.com/show/3982/windows-phone-7-review
238
314
  - regex: '(MSIE) (\d+)\.(\d+).*XBLWP7'
239
315
  family_replacement: 'IE Large Screen'
240
316
 
241
- # AFTER THE EDGE CASES ABOVE!
242
- - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+)'
243
- - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*)?'
244
-
245
317
  #### END MAIN CASES ####
246
318
 
247
319
  #### SPECIAL CASES ####
@@ -255,20 +327,6 @@ user_agent_parsers:
255
327
  - regex: '(Maxthon|MyIE2|Uzbl|Shiira)'
256
328
  v1_replacement: '0'
257
329
 
258
- - regex: 'PLAYSTATION 3.+WebKit'
259
- family_replacement: 'NetFront NX'
260
- - regex: 'PLAYSTATION 3'
261
- family_replacement: 'NetFront'
262
- - regex: '(PlayStation Portable)'
263
- family_replacement: 'NetFront'
264
- - regex: '(PlayStation Vita)'
265
- family_replacement: 'NetFront NX'
266
-
267
- - regex: 'AppleWebKit.+ (NX)/(\d+)\.(\d+)\.(\d+)'
268
- family_replacement: 'NetFront NX'
269
- - regex: '(Nintendo 3DS)'
270
- family_replacement: 'NetFront NX'
271
-
272
330
  - regex: '(BrowseX) \((\d+)\.(\d+)\.(\d+)'
273
331
 
274
332
  - regex: '(NCSA_Mosaic)/(\d+)\.(\d+)'
@@ -280,11 +338,12 @@ user_agent_parsers:
280
338
  - regex: '(Embider)/(\d+)\.(\d+)'
281
339
  family_replacement: 'Polaris'
282
340
 
283
- - regex: '(BonEcho)/(\d+)\.(\d+)\.(\d+)'
341
+ - regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+)?'
284
342
  family_replacement: 'Bon Echo'
285
343
 
286
- - regex: 'M?QQBrowser'
287
- family_replacement: 'QQ Browser'
344
+ # @note: iOS / OSX Applications
345
+ - regex: '(CFNetwork)(?:/(\d+)\.(\d+)\.?(\d+)?)?'
346
+ family_replacement: 'CFNetwork'
288
347
 
289
348
  - regex: '(iPod).+Version/(\d+)\.(\d+)\.(\d+)'
290
349
  family_replacement: 'Mobile Safari'
@@ -298,7 +357,7 @@ user_agent_parsers:
298
357
  family_replacement: 'Mobile Safari'
299
358
  - regex: '(iPad).*Version/(\d+)\.(\d+)'
300
359
  family_replacement: 'Mobile Safari'
301
- - regex: '(iPod|iPhone|iPad);.*CPU.*OS (\d+)(?:_\d+)?_(\d+).*Mobile'
360
+ - regex: '(iPod|iPhone|iPad);.*CPU.*OS (\d+)_(\d+)(?:_(\d+))?.*Mobile'
302
361
  family_replacement: 'Mobile Safari'
303
362
  - regex: '(iPod|iPhone|iPad)'
304
363
  family_replacement: 'Mobile Safari'
@@ -315,8 +374,10 @@ user_agent_parsers:
315
374
  - regex: '(QtCarBrowser)'
316
375
  v1_replacement: '1'
317
376
 
318
- - regex: '(iBrowser/Mini)(\d+).(\d+)'
377
+ - regex: '^(iBrowser/Mini)(\d+).(\d+)'
319
378
  family_replacement: 'iBrowser Mini'
379
+ - regex: '^(iBrowser|iRAPP)/(\d+).(\d+)'
380
+
320
381
  # nokia browsers
321
382
  # based on: http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices
322
383
  - regex: '^(Nokia)'
@@ -367,10 +428,6 @@ user_agent_parsers:
367
428
  #- regex: '\(iPad;.+(Version)/(\d+)\.(\d+)(?:\.(\d+))?.*Safari/'
368
429
  # family_replacement: 'iPad'
369
430
 
370
- # Amazon Silk, should go before Safari
371
- - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
372
- family_replacement: 'Amazon Silk'
373
-
374
431
  # Phantomjs, should go before Safari
375
432
  - regex: '(PhantomJS)/(\d+)\.(\d+)\.(\d+)'
376
433
 
@@ -397,10 +454,25 @@ user_agent_parsers:
397
454
  - regex: '(Phantom)/V(\d+)\.(\d+)'
398
455
  family_replacement: 'Phantom Browser'
399
456
 
400
- - regex: '([MS]?IE) (\d+)\.(\d+)'
457
+ - regex: 'Trident(.*)rv.(\d+)\.(\d+)'
401
458
  family_replacement: 'IE'
402
459
 
403
- - regex: 'Trident(.*)rv.(\d+)\.(\d+)'
460
+ # Espial
461
+ - regex: '(Espial)/(\d+)(?:\.(\d+))?(?:\.(\d+))?'
462
+
463
+ # Apple Mail
464
+
465
+ # apple mail - not directly detectable, have it after Safari stuff
466
+ - regex: '(AppleWebKit)/(\d+)\.(\d+)\.(\d+)'
467
+ family_replacement: 'AppleMail'
468
+
469
+ # AFTER THE EDGE CASES ABOVE!
470
+ # AFTER IE11
471
+ # BEFORE all other IE
472
+ - regex: '(Firefox)/(\d+)\.(\d+)\.(\d+)'
473
+ - regex: '(Firefox)/(\d+)\.(\d+)(pre|[ab]\d+[a-z]*)?'
474
+
475
+ - regex: '([MS]?IE) (\d+)\.(\d+)'
404
476
  family_replacement: 'IE'
405
477
 
406
478
  - regex: '(python-requests)/(\d+)\.(\d+)'
@@ -465,13 +537,22 @@ os_parsers:
465
537
  # generic HbbTV, hoping to catch manufacturer name (always after 2nd comma) and the first string that looks like a 2011-2019 year
466
538
  - regex: 'HbbTV/\d+\.\d+\.\d+ \(.*; ?([a-zA-Z]+) ?;.*(201[1-9]).*\)'
467
539
 
540
+ ##########
541
+ # @note: Windows Phone needs to come before Windows NT 6.1 *and* before Android to catch cases such as:
542
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920)...
543
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; ANZ821)...
544
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Orange)...
545
+ # Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 920; Vodafone)...
546
+ ##########
547
+
548
+ - regex: '(Windows Phone) (?:OS[ /])?(\d+)\.(\d+)'
549
+
468
550
  ##########
469
551
  # Android
470
552
  # can actually detect rooted android os. do we care?
471
553
  ##########
472
- - regex: '(Android) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?'
473
- - regex: '(Android)\-(\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?'
474
-
554
+ - regex: '(Android)[ \-/](\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?'
555
+
475
556
  - regex: '(Android) Donut'
476
557
  os_v1_replacement: '1'
477
558
  os_v2_replacement: '2'
@@ -491,6 +572,17 @@ os_parsers:
491
572
  - regex: '(Android) Honeycomb'
492
573
  os_v1_replacement: '3'
493
574
 
575
+ # UCWEB
576
+ - regex: '^UCWEB.*; (Adr) (\d+)\.(\d+)(?:[.\-]([a-z0-9]+))?;'
577
+ os_replacement: 'Android'
578
+ - regex: '^UCWEB.*; (iPad OS|iPh OS) (\d+)_(\d+)(?:_(\d+))?;'
579
+ os_replacement: 'iOS'
580
+ - regex: '^UCWEB.*; (wds) (\d+)\.(\d+)(?:\.(\d+))?;'
581
+ os_replacement: 'Windows Phone'
582
+ # JUC
583
+ - regex: '^(JUC).*; ?U; ?(?:Android)?(\d+)\.(\d+)(?:[\.\-]([a-z0-9]+))?'
584
+ os_replacement: 'Android'
585
+
494
586
  ##########
495
587
  # Kindle Android
496
588
  ##########
@@ -506,14 +598,18 @@ os_parsers:
506
598
  # (very) roughly ordered in terms of frequency of occurence of regex (win xp currently most frequent, etc)
507
599
  ##########
508
600
 
509
- - regex: '(Windows (?:NT 5\.2|NT 5\.1))'
510
- os_replacement: 'Windows XP'
511
-
512
- # ie mobile des ktop mode
601
+ # ie mobile desktop mode
513
602
  # spoofs nt 6.1. must come before windows 7
514
603
  - regex: '(XBLWP7)'
515
604
  os_replacement: 'Windows Phone'
516
605
 
606
+ # @note: This needs to come before Windows NT 6.1
607
+ - regex: '(Windows ?Mobile)'
608
+ os_replacement: 'Windows Mobile'
609
+
610
+ - regex: '(Windows (?:NT 5\.2|NT 5\.1))'
611
+ os_replacement: 'Windows XP'
612
+
517
613
  - regex: '(Windows NT 6\.1)'
518
614
  os_replacement: 'Windows 7'
519
615
 
@@ -521,30 +617,37 @@ os_parsers:
521
617
  os_replacement: 'Windows Vista'
522
618
 
523
619
  - regex: '(Win 9x 4\.90)'
524
- os_replacement: 'Windows Me'
620
+ os_replacement: 'Windows ME'
525
621
 
526
622
  - regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)'
527
623
 
528
624
  - regex: '(Windows NT 6\.2; ARM;)'
529
625
  os_replacement: 'Windows RT'
530
-
531
- # is this a spoof or is nt 6.2 out and about in some capacity?
532
626
  - regex: '(Windows NT 6\.2)'
533
627
  os_replacement: 'Windows 8'
534
628
 
629
+ - regex: '(Windows NT 6\.3; ARM;)'
630
+ os_replacement: 'Windows RT 8.1'
631
+ - regex: '(Windows NT 6\.3)'
632
+ os_replacement: 'Windows 8.1'
633
+
535
634
  - regex: '(Windows NT 5\.0)'
536
635
  os_replacement: 'Windows 2000'
537
636
 
538
- - regex: '(Windows Phone) (\d+)\.(\d+)'
539
- - regex: '(Windows Phone) OS (\d+)\.(\d+)'
540
- - regex: '(Windows ?Mobile)'
541
- os_replacement: 'Windows Mobile'
542
-
543
637
  - regex: '(WinNT4.0)'
544
638
  os_replacement: 'Windows NT 4.0'
545
639
 
546
- - regex: '(Win98)'
547
- os_replacement: 'Windows 98'
640
+ - regex: '(Windows ?CE)'
641
+ os_replacement: 'Windows CE'
642
+
643
+ - regex: 'Win ?(95|98|3.1|NT|ME|2000)'
644
+ os_replacement: 'Windows $1'
645
+
646
+ - regex: 'Win16'
647
+ os_replacement: 'Windows 3.1'
648
+
649
+ - regex: 'Win32'
650
+ os_replacement: 'Windows 95'
548
651
 
549
652
  ##########
550
653
  # Tizen OS from Samsung
@@ -554,10 +657,36 @@ os_parsers:
554
657
 
555
658
  ##########
556
659
  # Mac OS
557
- # http://en.wikipedia.org/wiki/Mac_OS_X#Versions
660
+ # @ref: http://en.wikipedia.org/wiki/Mac_OS_X#Versions
661
+ # @ref: http://www.puredarwin.org/curious/versions
558
662
  ##########
559
663
  - regex: '(Mac OS X) (\d+)[_.](\d+)(?:[_.](\d+))?'
560
-
664
+ # Leopard
665
+ - regex: ' (Dar)(win)/(9).(\d+).*\((?:i386|x86_64|Power Macintosh)\)'
666
+ os_replacement: 'Mac OS X'
667
+ os_v1_replacement: '10'
668
+ os_v2_replacement: '5'
669
+ # Snow Leopard
670
+ - regex: ' (Dar)(win)/(10).(\d+).*\((?:i386|x86_64)\)'
671
+ os_replacement: 'Mac OS X'
672
+ os_v1_replacement: '10'
673
+ os_v2_replacement: '6'
674
+ # Lion
675
+ - regex: ' (Dar)(win)/(11).(\d+).*\((?:i386|x86_64)\)'
676
+ os_replacement: 'Mac OS X'
677
+ os_v1_replacement: '10'
678
+ os_v2_replacement: '7'
679
+ # Mountain Lion
680
+ - regex: ' (Dar)(win)/(12).(\d+).*\((?:i386|x86_64)\)'
681
+ os_replacement: 'Mac OS X'
682
+ os_v1_replacement: '10'
683
+ os_v2_replacement: '8'
684
+ # Mavericks
685
+ - regex: ' (Dar)(win)/(13).(\d+).*\((?:i386|x86_64)\)'
686
+ os_replacement: 'Mac OS X'
687
+ os_v1_replacement: '10'
688
+ os_v2_replacement: '9'
689
+
561
690
  # IE on Mac doesn't specify version number
562
691
  - regex: 'Mac_PowerPC'
563
692
  os_replacement: 'Mac OS'
@@ -571,7 +700,7 @@ os_parsers:
571
700
  # iOS
572
701
  # http://en.wikipedia.org/wiki/IOS_version_history
573
702
  ##########
574
- - regex: '(CPU OS|iPhone OS) (\d+)_(\d+)(?:_(\d+))?'
703
+ - regex: '(CPU OS|iPhone OS|CPU iPhone) +(\d+)[_\.](\d+)(?:[_\.](\d+))?'
575
704
  os_replacement: 'iOS'
576
705
 
577
706
  # remaining cases are mostly only opera uas, so catch opera as to not catch iphone spoofs
@@ -585,6 +714,63 @@ os_parsers:
585
714
  - regex: '(AppleTV)/(\d+)\.(\d+)'
586
715
  os_replacement: 'ATV OS X'
587
716
 
717
+ # CFNetwork/Darwin - The specific CFNetwork or Darwin version determines
718
+ # whether the os maps to Mac OS, or iOS, or just Darwin.
719
+ # See: http://user-agents.me/cfnetwork-version-list
720
+ - regex: '(CFNetwork)/(5)48\.0\.3.* Darwin/11\.0\.0'
721
+ os_replacement: 'iOS'
722
+ - regex: '(CFNetwork)/(5)48\.(0)\.4.* Darwin/(1)1\.0\.0'
723
+ os_replacement: 'iOS'
724
+ - regex: '(CFNetwork)/(5)48\.(1)\.4'
725
+ os_replacement: 'iOS'
726
+ - regex: '(CFNetwork)/(4)85\.1(3)\.9'
727
+ os_replacement: 'iOS'
728
+ - regex: '(CFNetwork)/(6)09\.(1)\.4'
729
+ os_replacement: 'iOS'
730
+ - regex: '(CFNetwork)/(6)(0)9'
731
+ os_replacement: 'iOS'
732
+ - regex: '(CFNetwork)/6(7)2\.(1)\.13'
733
+ os_replacement: 'iOS'
734
+ - regex: '(CFNetwork)/6(7)2\.(1)\.(1)4'
735
+ os_replacement: 'iOS'
736
+ - regex: '(CF)(Network)/6(7)(2)\.1\.15'
737
+ os_replacement: 'iOS'
738
+ os_v1_replacement: '7'
739
+ os_v2_replacement: '1'
740
+ - regex: '(CFNetwork)/6(7)2\.(0)\.(?:2|8)'
741
+ os_replacement: 'iOS'
742
+ - regex: '(CFNetwork)/709\.1'
743
+ os_replacement: 'iOS'
744
+ os_v1_replacement: '8'
745
+ os_v2_replacement: '0.b5'
746
+
747
+ ##########
748
+ # CFNetwork iOS Apps
749
+ # @ref: https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
750
+ ##########
751
+ - regex: 'CFNetwork/.* Darwin/(9)\.\d+'
752
+ os_replacement: 'iOS'
753
+ os_v1_replacement: '1'
754
+ - regex: 'CFNetwork/.* Darwin/(10)\.\d+'
755
+ os_replacement: 'iOS'
756
+ os_v1_replacement: '4'
757
+ - regex: 'CFNetwork/.* Darwin/(11)\.\d+'
758
+ os_replacement: 'iOS'
759
+ os_v1_replacement: '5'
760
+ - regex: 'CFNetwork/.* Darwin/(13)\.\d+'
761
+ os_replacement: 'iOS'
762
+ os_v1_replacement: '6'
763
+ - regex: 'CFNetwork/6.* Darwin/(14)\.\d+'
764
+ os_replacement: 'iOS'
765
+ os_v1_replacement: '7'
766
+ - regex: 'CFNetwork/7.* Darwin/(14)\.\d+'
767
+ os_replacement: 'iOS'
768
+ os_v1_replacement: '8'
769
+ os_v2_replacement: '0'
770
+ # iOS Apps
771
+ - regex: '\b(iOS[ /]|iPhone(?:/| v|[ _]OS[/,]|; | OS : |\d,\d/|\d,\d; )|iPad/)(\d{1,2})[_\.](\d{1,2})(?:[_\.](\d+))?'
772
+ os_replacement: 'iOS'
773
+
588
774
  ##########
589
775
  # Chrome OS
590
776
  # if version 0.0.0, probably this stuff:
@@ -606,7 +792,7 @@ os_parsers:
606
792
  # Symbian + Symbian OS
607
793
  # http://en.wikipedia.org/wiki/History_of_Symbian
608
794
  ##########
609
- - regex: '(Symbian[Oo][Ss])/(\d+)\.(\d+)'
795
+ - regex: '(Symbian[Oo][Ss])[/ ](\d+)\.(\d+)'
610
796
  os_replacement: 'Symbian OS'
611
797
  - regex: '(Symbian/3).+NokiaBrowser/7\.3'
612
798
  os_replacement: 'Symbian^3 Anna'
@@ -614,13 +800,15 @@ os_parsers:
614
800
  os_replacement: 'Symbian^3 Belle'
615
801
  - regex: '(Symbian/3)'
616
802
  os_replacement: 'Symbian^3'
617
- - regex: '(Series 60|SymbOS|S60)'
803
+ - regex: '\b(Series 60|SymbOS|S60Version|S60V\d|S60\b)'
618
804
  os_replacement: 'Symbian OS'
619
805
  - regex: '(MeeGo)'
620
806
  - regex: 'Symbian [Oo][Ss]'
621
807
  os_replacement: 'Symbian OS'
622
808
  - regex: 'Series40;'
623
809
  os_replacement: 'Nokia Series 40'
810
+ - regex: 'Series30Plus;'
811
+ os_replacement: 'Nokia Series 30 Plus'
624
812
 
625
813
  ##########
626
814
  # BlackBerry devices
@@ -641,7 +829,7 @@ os_parsers:
641
829
  ##########
642
830
  # Firefox OS
643
831
  ##########
644
- - regex: '\(Mobile;.+Firefox/\d+\.\d+'
832
+ - regex: '\((?:Mobile|Tablet);.+Firefox/\d+\.\d+'
645
833
  os_replacement: 'Firefox OS'
646
834
 
647
835
  ##########
@@ -658,12 +846,10 @@ os_parsers:
658
846
  ##########
659
847
  # Google TV
660
848
  ##########
661
- - regex: '(GoogleTV) (\d+)\.(\d+)\.(\d+)'
662
- # Old style
663
- - regex: '(GoogleTV)/[\da-z]+'
849
+ - regex: '(GoogleTV)(?: (\d+)\.(\d+)(?:\.(\d+))?|/[\da-z]+)'
664
850
 
665
851
  - regex: '(WebTV)/(\d+).(\d+)'
666
-
852
+
667
853
  ##########
668
854
  # Misc mobile
669
855
  ##########
@@ -675,20 +861,20 @@ os_parsers:
675
861
  # Generic patterns
676
862
  # since the majority of os cases are very specific, these go last
677
863
  ##########
678
- # first.second.third.fourth bits
679
- - regex: '(Fedora|Red Hat|PCLinuxOS)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
864
+ - regex: '(Fedora|Red Hat|PCLinuxOS|Puppy|Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Slackware|(?:Free|Open|Net|\b)BSD)[/ ](\d+)\.(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
680
865
 
681
- # first.second.third bits
682
- - regex: '(Red Hat|Puppy|PCLinuxOS)/(\d+)\.(\d+)\.(\d+)'
866
+ # Gentoo Linux + Kernel Version
867
+ - regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+))?.*gentoo'
868
+ os_replacement: 'Gentoo'
683
869
 
684
- # first.second bits
685
- - regex: '(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\d+)\.(\d+)'
870
+ # Opera Mini Bada
871
+ - regex: '\((Bada);'
686
872
 
687
873
  # just os
688
- - regex: '(Windows|OpenBSD|FreeBSD|NetBSD|Android|WeTab)'
689
- - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Gentoo|Mageia)'
690
- - regex: '(Linux)/(\d+)\.(\d+)'
691
- - regex: '(Linux|BSD)'
874
+ - regex: '(Windows|Android|WeTab|Maemo)'
875
+ - regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Gentoo|Mageia|(?:Free|Open|Net|\b)BSD)'
876
+ # Linux + Kernel Version
877
+ - regex: '(Linux)(?:[ /](\d+)\.(\d+)(?:\.(\d+))?)?'
692
878
  - regex: 'SunOS'
693
879
  os_replacement: 'Solaris'
694
880
 
@@ -734,7 +920,29 @@ device_parsers:
734
920
  # Samsung
735
921
  - regex: '(SamsungSGHi560)'
736
922
  device_replacement: 'Samsung SGHi560'
923
+
924
+ - regex: '(SCH-[A-Za-z0-9_-]+)'
925
+ device_replacement: 'Samsung $1'
926
+
927
+ - regex: '(SGH-[A-Za-z0-9_-]+)'
928
+ device_replacement: 'Samsung $1'
929
+
930
+ - regex: '(GT-[A-Za-z0-9_-]+)'
931
+ device_replacement: 'Samsung $1'
932
+
933
+ - regex: '(SM-[A-Za-z0-9_-]+)'
934
+ device_replacement: 'Samsung $1'
935
+
936
+ - regex: '(SPH-[A-Za-z0-9_-]+)'
937
+ device_replacement: 'Samsung $1'
737
938
 
939
+ - regex: 'SAMSUNG-([A-Za-z0-9_-]+)'
940
+ device_replacement: 'Samsung $1'
941
+
942
+ - regex: 'SAMSUNG ([A-Za-z0-9_-]+)'
943
+ device_replacement: 'Samsung $1'
944
+
945
+
738
946
  #########
739
947
  # Ericsson - must come before nokia since they also use symbian
740
948
  #########
@@ -747,8 +955,8 @@ device_parsers:
747
955
  ##########
748
956
  - regex: 'PLAYSTATION 3'
749
957
  device_replacement: 'PlayStation 3'
750
- - regex: '(PlayStation Portable)'
751
- - regex: '(PlayStation Vita)'
958
+ - regex: '(PlayStation (:?Portable|Vita))'
959
+ - regex: '(PlayStation (:?\d+))'
752
960
 
753
961
  ##########
754
962
  # incomplete!
@@ -763,21 +971,22 @@ device_parsers:
763
971
  device_replacement: 'Kindle Fire HD 8.9" WiFi'
764
972
  - regex: '(KFJWA Build)'
765
973
  device_replacement: 'Kindle Fire HD 8.9" 4G'
974
+ - regex: '(KFSOWI Build)'
975
+ device_replacement: 'Kindle Fire HD 7" WiFi'
976
+ - regex: '(KFTHWI Build)'
977
+ device_replacement: 'Kindle Fire HDX 7" WiFi'
978
+ - regex: '(KFTHWA Build)'
979
+ device_replacement: 'Kindle Fire HDX 7" 4G'
980
+ - regex: '(KFAPWI Build)'
981
+ device_replacement: 'Kindle Fire HDX 8.9" WiFi'
982
+ - regex: '(KFAPWA Build)'
983
+ device_replacement: 'Kindle Fire HDX 8.9" 4G'
766
984
  - regex: '(Kindle Fire)'
767
985
  - regex: '(Kindle)'
768
986
  - regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
769
987
  device_replacement: 'Kindle Fire'
770
988
 
771
- #########
772
- # Android General Device Matching (far from perfect)
773
- #########
774
- - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; WOWMobile (.+) Build'
775
- - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{0,2}; (.+) Build'
776
- - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; (.+) Build'
777
- - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+;[A-Za-z]{2}\-[A-Za-z]{0,2};(.+) Build'
778
- - regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{0,2}; (.+) Build'
779
- - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; (.+) Build'
780
- - regex: 'Android[\- ][\d]+\.[\d]+; (.+) Build'
989
+
781
990
 
782
991
  ##########
783
992
  # NOKIA
@@ -849,7 +1058,16 @@ device_parsers:
849
1058
 
850
1059
  - regex: 'Googlebot-Mobile/(\d+).(\d+)'
851
1060
  device_replacement: 'Spider'
1061
+
1062
+ - regex: 'Googlebot/\d+.\d+'
1063
+ device_replacement: 'Spider'
1064
+
1065
+ - regex: 'NING/(\d+).(\d+)'
1066
+ device_replacement: 'Spider'
852
1067
 
1068
+ - regex: 'MsnBot-Media /(\d+).(\d+)'
1069
+ device_replacement: 'Spider'
1070
+
853
1071
  ##########
854
1072
  # complete but probably catches spoofs
855
1073
  # iSTUFF
@@ -878,7 +1096,14 @@ device_parsers:
878
1096
  device_replacement: 'Alcatel $1'
879
1097
  - regex: 'Alcatel-([A-Za-z0-9]+)'
880
1098
  device_replacement: 'Alcatel $1'
881
-
1099
+ - regex: 'ALCATEL_ONE_TOUCH_([A-Za-z0-9]+)'
1100
+ device_replacement: 'Alcatel ONE TOUCH $1'
1101
+ - regex: 'ALCATEL (ONE TOUCH [A-Za-z0-9]+)'
1102
+ device_replacement: 'Alcatel $1'
1103
+ - regex: 'ALCATEL (one touch [A-Za-z0-9]+)'
1104
+ device_replacement: 'Alcatel $1'
1105
+ - regex: 'ALCATEL ([A-Za-z0-9]+)'
1106
+ device_replacement: 'Alcatel $1'
882
1107
  ##########
883
1108
  # Amoi
884
1109
  ##########
@@ -997,6 +1222,14 @@ device_parsers:
997
1222
  device_replacement: 'Motorola $1'
998
1223
  - regex: 'MOT\-([A-Za-z0-9]+)'
999
1224
  device_replacement: 'Motorola $1'
1225
+ - regex: ' (DROID RAZR [A-Za-z0-9 ]+) '
1226
+ device_replacement: 'Motorola $1'
1227
+ - regex: ' (DROID[2 ][A-Za-z0-9 ]+) '
1228
+ device_replacement: 'Motorola $1'
1229
+ - regex: ' (Droid2| )'
1230
+ device_replacement: 'Motorola $1'
1231
+ - regex: ' (DROID2| )'
1232
+ device_replacement: 'Motorola $1'
1000
1233
 
1001
1234
  ##########
1002
1235
  # nintendo
@@ -1027,6 +1260,16 @@ device_parsers:
1027
1260
  device_replacement: 'Samsung $1'
1028
1261
  - regex: 'SAMSUNG\; ([A-Za-z0-9\-]+)'
1029
1262
  device_replacement: 'Samsung $1'
1263
+
1264
+ ##########
1265
+ # ZTE
1266
+ ##########
1267
+ - regex: 'ZTE-([A-Za-z0-9\-]+)'
1268
+ device_replacement: 'ZTE $1'
1269
+ - regex: 'ZTE ([A-Za-z0-9\-]+)'
1270
+ device_replacement: 'ZTE $1'
1271
+ - regex: 'ZTE_([A-Za-z0-9\-]+)'
1272
+ device_replacement: 'ZTE $1'
1030
1273
 
1031
1274
  ##########
1032
1275
  # Sega
@@ -1042,11 +1285,30 @@ device_parsers:
1042
1285
  - regex: 'Softbank/2\.0/([A-Za-z0-9]+)'
1043
1286
  device_replacement: 'Softbank $1'
1044
1287
 
1288
+ ##########
1289
+ # SONY #
1290
+ ##########
1291
+ - regex: 'Sony([^ ]+) '
1292
+ device_replacement: 'Sony $1'
1293
+
1045
1294
  ##########
1046
1295
  # WebTV
1047
1296
  ##########
1048
1297
  - regex: '(WebTV)/(\d+).(\d+)'
1049
1298
 
1299
+ #########
1300
+ # Android General Device Matching (far from perfect)
1301
+ #########
1302
+ - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; [^;]+; ([A-Za-z0-9 _-]+) '
1303
+ - regex: 'Android[\- ][\d]+\.[\d]+; [^;]+; ([A-Za-z0-9 _-]+) '
1304
+ - regex: 'Android[\- ][\d]+\.[\d]+; [^;]+; WOWMobile ([A-Za-z0-9 _-]+) '
1305
+ - regex: 'Android[\- ][\d]+\.[\d]+\-update1; [^;]+; ([A-Za-z0-9 _-]+) '
1306
+ - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+;[^;]+;([A-Za-z0-9 _-]+) '
1307
+ - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; ([A-Za-z0-9 _-]+) '
1308
+ - regex: 'Android[\- ][\d]+\.[\d]+; ([A-Za-z0-9 _-]+) '
1309
+ - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; [^;]+; ([A-Za-z0-9\.\/_-]+) '
1310
+ - regex: 'Android[\- ][\d]+\.[\d]+; [^;]+; ([A-Za-z0-9\.\/_-]+) '
1311
+
1050
1312
  ##########
1051
1313
  # Generic Smart Phone
1052
1314
  ##########
@@ -1068,6 +1330,6 @@ device_parsers:
1068
1330
  ##########
1069
1331
  # Spiders (this is hack...)
1070
1332
  ##########
1071
- - regex: '(bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\-webcrawler|converacrawler|dataparksearch|findlinks|crawler)'
1333
+ - regex: '(bingbot|bot|borg|google(^tv)|yahoo|slurp|msnbot|msrbot|openbot|archiver|netresearch|lycos|scooter|altavista|teoma|gigabot|baiduspider|blitzbot|oegp|charlotte|furlbot|http%20client|polybot|htdig|ichiro|mogimogi|larbin|pompos|scrubby|searchsight|seekbot|semanticdiscovery|silk|snappy|speedy|spider|voila|vortex|voyager|zao|zeal|fast\-webcrawler|converacrawler|dataparksearch|findlinks|crawler|Netvibes|Sogou Pic Spider|ICC\-Crawler|Innovazion Crawler|Daumoa|EtaoSpider|A6\-Indexer|YisouSpider|Riddler|DBot|wsr\-agent|Xenu|SeznamBot|PaperLiBot|SputnikBot|CCBot|ProoXiBot|Scrapy|Genieo|Screaming Frog|YahooCacheSystem|CiBra|Nutch)'
1072
1334
  device_replacement: 'Spider'
1073
1335
 
metadata CHANGED
@@ -1,25 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: user_agent_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Lucas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-28 00:00:00.000000000 Z
11
+ date: 2014-11-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A simple, comprehensive Ruby gem for parsing user agent strings with
14
14
  the help of BrowserScope's UA database
15
15
  email: t@toolmantim.com
16
- executables: []
16
+ executables:
17
+ - user_agent_parser
17
18
  extensions: []
18
19
  extra_rdoc_files: []
19
20
  files:
20
21
  - MIT-LICENSE
21
22
  - Readme.md
23
+ - bin/user_agent_parser
22
24
  - lib/user_agent_parser.rb
25
+ - lib/user_agent_parser/cli.rb
23
26
  - lib/user_agent_parser/device.rb
24
27
  - lib/user_agent_parser/operating_system.rb
25
28
  - lib/user_agent_parser/parser.rb
@@ -46,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
49
  version: '0'
47
50
  requirements: []
48
51
  rubyforge_project:
49
- rubygems_version: 2.1.10
52
+ rubygems_version: 2.2.2
50
53
  signing_key:
51
54
  specification_version: 4
52
55
  summary: A simple, comprehensive Ruby gem for parsing user agent strings with the