user_agent_parser 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

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