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 +4 -4
- data/Readme.md +19 -3
- data/bin/user_agent_parser +59 -0
- data/lib/user_agent_parser/cli.rb +58 -0
- data/lib/user_agent_parser/device.rb +7 -5
- data/lib/user_agent_parser/operating_system.rb +7 -5
- data/lib/user_agent_parser/parser.rb +6 -6
- data/lib/user_agent_parser/user_agent.rb +6 -7
- data/lib/user_agent_parser/version.rb +9 -4
- data/vendor/ua-parser/regexes.yaml +356 -94
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e6c42fb7a24030be52fa5c096b8af27e362bb02
|
4
|
+
data.tar.gz: 60cfeb6d90444739f7f81f0e035704e23b5597df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
##
|
5
|
+
## Supported Rubies
|
6
6
|
|
7
|
-
* Ruby
|
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.
|
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 :
|
3
|
+
attr_reader :family
|
4
4
|
|
5
|
-
|
6
|
-
|
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
|
-
|
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) &&
|
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 :
|
3
|
+
attr_reader :family, :version
|
4
4
|
|
5
|
-
|
6
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
141
|
-
|
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 :
|
3
|
+
attr_reader :family, :version, :os, :device
|
4
4
|
|
5
|
-
|
6
|
-
alias_method :family, :name
|
5
|
+
alias_method :name, :family
|
7
6
|
|
8
|
-
def initialize(
|
9
|
-
@
|
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 =
|
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
|
-
|
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,
|
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(
|
12
|
-
|
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+)
|
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)
|
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|
|
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|
|
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+)
|
341
|
+
- regex: '(BonEcho)/(\d+)\.(\d+)\.?([ab]?\d+)?'
|
284
342
|
family_replacement: 'Bon Echo'
|
285
343
|
|
286
|
-
|
287
|
-
|
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+)(
|
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: '(
|
457
|
+
- regex: 'Trident(.*)rv.(\d+)\.(\d+)'
|
401
458
|
family_replacement: 'IE'
|
402
459
|
|
403
|
-
|
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
|
-
|
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
|
-
|
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
|
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: '(
|
547
|
-
os_replacement: 'Windows
|
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+)
|
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
|
-
|
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
|
-
#
|
682
|
-
- regex: '(
|
866
|
+
# Gentoo Linux + Kernel Version
|
867
|
+
- regex: '(Linux)[ /](\d+)\.(\d+)(?:\.(\d+))?.*gentoo'
|
868
|
+
os_replacement: 'Gentoo'
|
683
869
|
|
684
|
-
#
|
685
|
-
- regex: '(
|
870
|
+
# Opera Mini Bada
|
871
|
+
- regex: '\((Bada);'
|
686
872
|
|
687
873
|
# just os
|
688
|
-
- regex: '(Windows|
|
689
|
-
- regex: '(Ubuntu|Kubuntu|Arch Linux|CentOS|Slackware|Gentoo|openSUSE|SUSE|Red Hat|Fedora|PCLinuxOS|Gentoo|Mageia)'
|
690
|
-
|
691
|
-
- regex: '(Linux
|
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
|
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.
|
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:
|
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.
|
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
|