user_agent_parser 1.0.2 → 2.0.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.
- data/Readme.md +25 -28
- data/lib/user_agent_parser.rb +4 -15
- data/lib/user_agent_parser/device.rb +23 -0
- data/lib/user_agent_parser/operating_system.rb +20 -18
- data/lib/user_agent_parser/parser.rb +101 -48
- data/lib/user_agent_parser/user_agent.rb +20 -16
- data/lib/user_agent_parser/version.rb +30 -20
- data/vendor/ua-parser/regexes.yaml +216 -118
- metadata +4 -3
data/Readme.md
CHANGED
|
@@ -4,9 +4,7 @@ UserAgentParser is a simple, comprehensive Ruby gem for parsing user agent strin
|
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
-
* Ruby >= 1.
|
|
8
|
-
|
|
9
|
-
Note: Ruby 1.8.7 is not supported due to the requirement for the newer psych YAML parser. If you can get it working on 1.8.7 please send a pull request.
|
|
7
|
+
* Ruby >= 1.8.7
|
|
10
8
|
|
|
11
9
|
## Installation
|
|
12
10
|
|
|
@@ -19,49 +17,48 @@ $ gem install user_agent_parser
|
|
|
19
17
|
```ruby
|
|
20
18
|
require 'user_agent_parser'
|
|
21
19
|
=> true
|
|
22
|
-
|
|
20
|
+
user_agent = UserAgentParser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
|
|
23
21
|
=> #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
|
|
24
|
-
|
|
22
|
+
user_agent.to_s
|
|
25
23
|
=> "IE 9.0"
|
|
26
|
-
|
|
24
|
+
user_agent.name
|
|
27
25
|
=> "IE"
|
|
28
|
-
|
|
26
|
+
user_agent.version.to_s
|
|
29
27
|
=> "9.0"
|
|
30
|
-
|
|
31
|
-
=> 9
|
|
32
|
-
|
|
33
|
-
=> 0
|
|
34
|
-
|
|
28
|
+
user_agent.version.major
|
|
29
|
+
=> "9"
|
|
30
|
+
user_agent.version.minor
|
|
31
|
+
=> "0"
|
|
32
|
+
operating_system = user_agent.os
|
|
35
33
|
=> #<UserAgentParser::OperatingSystem Windows Vista>
|
|
36
|
-
|
|
34
|
+
operating_system.to_s
|
|
37
35
|
=> "Windows Vista"
|
|
36
|
+
|
|
37
|
+
# The parser database will be loaded and parsed on every call to
|
|
38
|
+
# UserAgentParser.parse. To avoid this, instantiate your own Parser instance.
|
|
39
|
+
parser = UserAgentParser::Parser.new
|
|
40
|
+
parser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
|
|
41
|
+
=> #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
|
|
42
|
+
parser.parse 'Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53'
|
|
43
|
+
=> #<UserAgentParser::UserAgent Opera 10.53 (Windows XP)>
|
|
38
44
|
```
|
|
39
45
|
|
|
40
46
|
## The pattern database
|
|
41
47
|
|
|
42
48
|
The [ua-parser database](https://github.com/tobie/ua-parser/blob/master/regexes.yaml) is included via a [git submodule](http://help.github.com/submodules/). To update the database the submodule needs to be updated and the gem re-released (pull requests for this are very welcome!).
|
|
43
49
|
|
|
44
|
-
You can also specify the path to your own, updated and/or customised `regexes.yaml` file
|
|
50
|
+
You can also specify the path to your own, updated and/or customised `regexes.yaml` file as a second argument to `UserAgentParser.parse`:
|
|
45
51
|
|
|
46
52
|
```ruby
|
|
47
|
-
UserAgentParser.patterns_path
|
|
53
|
+
UserAgentParser.parse(ua_string, patterns_path: '/some/path/to/regexes.yaml')
|
|
48
54
|
```
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
$ rake test
|
|
54
|
-
...
|
|
55
|
-
|
|
56
|
-
Finished tests in 144.220280s, 89.0027 tests/s, 234.9739 assertions/s.
|
|
56
|
+
or when instantiating a `UserAgentParser::Parser`:
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
```ruby
|
|
59
|
+
UserAgentParser::Parser.new(patterns_path: '/some/path/to/regexes.yaml').parse(ua_string)
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
## Limitations
|
|
62
|
-
|
|
63
|
-
There's no support for providing overrides from Javascript user agent detection like there is with original BrowserScope library. The Javascript overrides were only necessary for detecting IE 9 Platform Preview and older versions of [Chrome Frame](https://developers.google.com/chrome/chrome-frame/).
|
|
64
|
-
|
|
65
62
|
## Contributing
|
|
66
63
|
|
|
67
64
|
1. Fork
|
|
@@ -73,4 +70,4 @@ All accepted pull requests will earn you commit and release rights.
|
|
|
73
70
|
|
|
74
71
|
## License
|
|
75
72
|
|
|
76
|
-
MIT
|
|
73
|
+
MIT
|
data/lib/user_agent_parser.rb
CHANGED
|
@@ -2,24 +2,13 @@ require 'user_agent_parser/parser'
|
|
|
2
2
|
require 'user_agent_parser/user_agent'
|
|
3
3
|
require 'user_agent_parser/version'
|
|
4
4
|
require 'user_agent_parser/operating_system'
|
|
5
|
+
require 'user_agent_parser/device'
|
|
5
6
|
|
|
6
7
|
module UserAgentParser
|
|
7
|
-
|
|
8
|
-
# Path to the ua-parser regexes pattern database
|
|
9
|
-
def self.patterns_path
|
|
10
|
-
@patterns_path
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Sets the path to the ua-parser regexes pattern database
|
|
14
|
-
def self.patterns_path=(path)
|
|
15
|
-
@patterns_path = path
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
self.patterns_path = File.join(File.dirname(__FILE__), "../vendor/ua-parser/regexes.yaml")
|
|
8
|
+
DefaultPatternsPath = File.join(File.dirname(__FILE__), "../vendor/ua-parser/regexes.yaml")
|
|
19
9
|
|
|
20
10
|
# Parse the given +user_agent_string+, returning a +UserAgent+
|
|
21
|
-
def self.parse
|
|
22
|
-
Parser.new.parse
|
|
11
|
+
def self.parse(user_agent_string, options={})
|
|
12
|
+
Parser.new(options).parse(user_agent_string)
|
|
23
13
|
end
|
|
24
|
-
|
|
25
14
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module UserAgentParser
|
|
2
|
+
class Device
|
|
3
|
+
attr_reader :name
|
|
4
|
+
|
|
5
|
+
def initialize(name = nil)
|
|
6
|
+
@name = name || 'Other'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def to_s
|
|
10
|
+
name
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def inspect
|
|
14
|
+
"#<#{self.class} #{to_s}>"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def eql?(other)
|
|
18
|
+
self.class.eql?(other.class) && name == other.name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
alias_method :==, :eql?
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
module UserAgentParser
|
|
2
|
-
|
|
3
2
|
class OperatingSystem
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
self.version = version
|
|
3
|
+
attr_reader :name, :version
|
|
4
|
+
|
|
5
|
+
def initialize(name = 'Other', version = nil)
|
|
6
|
+
@name = name
|
|
7
|
+
@version = version
|
|
10
8
|
end
|
|
11
|
-
|
|
9
|
+
|
|
12
10
|
def to_s
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
string = name
|
|
12
|
+
unless version.nil?
|
|
13
|
+
string += " #{version}"
|
|
14
|
+
end
|
|
15
|
+
string
|
|
16
16
|
end
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
def inspect
|
|
19
19
|
"#<#{self.class} #{to_s}>"
|
|
20
20
|
end
|
|
21
|
-
|
|
22
|
-
def
|
|
23
|
-
|
|
21
|
+
|
|
22
|
+
def eql?(other)
|
|
23
|
+
self.class.eql?(other.class) &&
|
|
24
|
+
name == other.name &&
|
|
25
|
+
version == other.version
|
|
24
26
|
end
|
|
25
|
-
|
|
26
|
-
end
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
alias_method :==, :eql?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -1,41 +1,49 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
2
|
|
|
3
3
|
module UserAgentParser
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
class Parser
|
|
6
|
+
attr_reader :patterns_path
|
|
6
7
|
|
|
7
|
-
def
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
ua
|
|
8
|
+
def initialize(options={})
|
|
9
|
+
@patterns_path = options[:patterns_path] || UserAgentParser::DefaultPatternsPath
|
|
10
|
+
@ua_patterns, @os_patterns, @device_patterns = load_patterns(patterns_path)
|
|
11
11
|
end
|
|
12
|
-
|
|
13
|
-
private
|
|
14
12
|
|
|
15
|
-
def
|
|
16
|
-
|
|
13
|
+
def parse(user_agent)
|
|
14
|
+
os = parse_os(user_agent)
|
|
15
|
+
device = parse_device(user_agent)
|
|
16
|
+
parse_ua(user_agent, os, device)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def load_patterns(path)
|
|
22
|
+
yml = YAML.load_file(path)
|
|
23
|
+
|
|
24
|
+
# Parse all the regexs
|
|
25
|
+
yml.each_pair do |type, patterns|
|
|
26
|
+
patterns.each do |pattern|
|
|
27
|
+
pattern["regex"] = Regexp.new(pattern["regex"])
|
|
24
28
|
end
|
|
25
29
|
end
|
|
30
|
+
|
|
31
|
+
[ yml["user_agent_parsers"], yml["os_parsers"], yml["device_parsers"] ]
|
|
26
32
|
end
|
|
27
|
-
|
|
28
|
-
def parse_ua
|
|
29
|
-
pattern, match = first_pattern_match(
|
|
33
|
+
|
|
34
|
+
def parse_ua(user_agent, os = nil, device = nil)
|
|
35
|
+
pattern, match = first_pattern_match(@ua_patterns, user_agent)
|
|
36
|
+
|
|
30
37
|
if match
|
|
31
|
-
user_agent_from_pattern_match(pattern, match)
|
|
38
|
+
user_agent_from_pattern_match(pattern, match, os, device)
|
|
32
39
|
else
|
|
33
|
-
UserAgent.new
|
|
40
|
+
UserAgent.new(nil, nil, os, device)
|
|
34
41
|
end
|
|
35
42
|
end
|
|
36
|
-
|
|
37
|
-
def parse_os
|
|
38
|
-
pattern, match = first_pattern_match(
|
|
43
|
+
|
|
44
|
+
def parse_os(user_agent)
|
|
45
|
+
pattern, match = first_pattern_match(@os_patterns, user_agent)
|
|
46
|
+
|
|
39
47
|
if match
|
|
40
48
|
os_from_pattern_match(pattern, match)
|
|
41
49
|
else
|
|
@@ -43,45 +51,90 @@ module UserAgentParser
|
|
|
43
51
|
end
|
|
44
52
|
end
|
|
45
53
|
|
|
46
|
-
def
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
def parse_device(user_agent)
|
|
55
|
+
pattern, match = first_pattern_match(@device_patterns, user_agent)
|
|
56
|
+
|
|
57
|
+
if match
|
|
58
|
+
device_from_pattern_match(pattern, match)
|
|
59
|
+
else
|
|
60
|
+
Device.new
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def first_pattern_match(patterns, value)
|
|
65
|
+
patterns.each do |pattern|
|
|
66
|
+
if match = pattern["regex"].match(value)
|
|
67
|
+
return [pattern, match]
|
|
50
68
|
end
|
|
51
69
|
end
|
|
52
70
|
nil
|
|
53
71
|
end
|
|
54
72
|
|
|
55
|
-
def user_agent_from_pattern_match
|
|
56
|
-
|
|
73
|
+
def user_agent_from_pattern_match(pattern, match, os = nil, device = nil)
|
|
74
|
+
name, v1, v2, v3 = match[1], match[2], match[3], match[4]
|
|
75
|
+
|
|
57
76
|
if pattern["family_replacement"]
|
|
58
|
-
|
|
77
|
+
name = pattern["family_replacement"].sub('$1', name || '')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if pattern["v1_replacement"]
|
|
81
|
+
v1 = pattern["v1_replacement"].sub('$1', v1 || '')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if pattern["v2_replacement"]
|
|
85
|
+
v2 = pattern["v2_replacement"].sub('$1', v2 || '')
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
if pattern["v3_replacement"]
|
|
89
|
+
v3 = pattern["v3_replacement"].sub('$1', v3 || '')
|
|
59
90
|
end
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
ua.version = version_from_segments(v1, v2, v3)
|
|
65
|
-
ua
|
|
91
|
+
|
|
92
|
+
version = version_from_segments(v1, v2, v3)
|
|
93
|
+
|
|
94
|
+
UserAgent.new(name, version, os, device)
|
|
66
95
|
end
|
|
67
|
-
|
|
68
|
-
def os_from_pattern_match
|
|
96
|
+
|
|
97
|
+
def os_from_pattern_match(pattern, match)
|
|
69
98
|
os, v1, v2, v3, v4 = match[1], match[2], match[3], match[4], match[5]
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
99
|
+
|
|
100
|
+
if pattern["os_replacement"]
|
|
101
|
+
os = pattern["os_replacement"].sub('$1', os || '')
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if pattern["os_v1_replacement"]
|
|
105
|
+
v1 = pattern["os_v1_replacement"].sub('$1', v1 || '')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
if pattern["os_v2_replacement"]
|
|
109
|
+
v2 = pattern["os_v2_replacement"].sub('$1', v2 || '')
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
if pattern["os_v3_replacement"]
|
|
113
|
+
v3 = pattern["os_v3_replacement"].sub('$1', v3 || '')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if pattern["os_v4_replacement"]
|
|
117
|
+
v4 = pattern["os_v4_replacement"].sub('$1', v4 || '')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
version = version_from_segments(v1, v2, v3, v4)
|
|
121
|
+
|
|
122
|
+
OperatingSystem.new(os, version)
|
|
78
123
|
end
|
|
79
|
-
|
|
124
|
+
|
|
125
|
+
def device_from_pattern_match(pattern, match)
|
|
126
|
+
device = match[1]
|
|
127
|
+
|
|
128
|
+
if pattern["device_replacement"]
|
|
129
|
+
device = pattern["device_replacement"].sub('$1', device || '')
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
Device.new(device)
|
|
133
|
+
end
|
|
134
|
+
|
|
80
135
|
def version_from_segments(*segments)
|
|
81
136
|
version_string = segments.compact.join(".")
|
|
82
137
|
version_string.empty? ? nil : Version.new(version_string)
|
|
83
138
|
end
|
|
84
|
-
|
|
85
139
|
end
|
|
86
|
-
|
|
87
140
|
end
|
|
@@ -1,33 +1,37 @@
|
|
|
1
1
|
module UserAgentParser
|
|
2
|
-
|
|
3
2
|
class UserAgent
|
|
3
|
+
attr_reader :name, :version, :os, :device
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# For backwards compatibility with older versions of this gem.
|
|
6
|
+
alias_method :family, :name
|
|
6
7
|
|
|
7
|
-
def initialize(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
def initialize(name = nil, version = nil, os = nil, device = nil)
|
|
9
|
+
@name = name || 'Other'
|
|
10
|
+
@version = version
|
|
11
|
+
@os = os
|
|
12
|
+
@device = device
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def to_s
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
string = name
|
|
17
|
+
string += " #{version}" if version
|
|
18
|
+
string
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def inspect
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
22
|
+
string = to_s
|
|
23
|
+
string += " (#{os})" if os
|
|
24
|
+
string += " (#{device})" if device
|
|
25
|
+
"#<#{self.class} #{string}>"
|
|
23
26
|
end
|
|
24
|
-
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
+
|
|
28
|
+
def eql?(other)
|
|
29
|
+
self.class.eql?(other.class) &&
|
|
30
|
+
name == other.name &&
|
|
27
31
|
version == other.version &&
|
|
28
32
|
os == other.os
|
|
29
33
|
end
|
|
30
34
|
|
|
35
|
+
alias_method :==, :eql?
|
|
31
36
|
end
|
|
32
|
-
|
|
33
37
|
end
|
|
@@ -1,37 +1,47 @@
|
|
|
1
1
|
module UserAgentParser
|
|
2
|
-
|
|
3
2
|
class Version
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
# Private: Regex used to split version string into major, minor, patch,
|
|
5
|
+
# and patch_minor.
|
|
6
|
+
SEGMENTS_REGEX = /\d+\-\d+|\d+[a-zA-Z]+$|\d+|[A-Za-z][0-9A-Za-z-]*$/
|
|
7
|
+
|
|
8
|
+
attr_reader :version
|
|
6
9
|
alias :to_s :version
|
|
7
10
|
|
|
8
11
|
def initialize(version)
|
|
9
|
-
|
|
12
|
+
@version = version.to_s.strip
|
|
10
13
|
end
|
|
11
14
|
|
|
12
|
-
def
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
def major
|
|
16
|
+
segments[0]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def minor
|
|
20
|
+
segments[1]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def patch
|
|
24
|
+
segments[2]
|
|
16
25
|
end
|
|
17
26
|
|
|
18
|
-
def
|
|
19
|
-
segments[
|
|
27
|
+
def patch_minor
|
|
28
|
+
segments[3]
|
|
20
29
|
end
|
|
21
|
-
|
|
22
|
-
def major; self[0] end
|
|
23
|
-
def minor; self[1] end
|
|
24
|
-
def patch; self[2] end
|
|
25
|
-
def patch_minor; self[3] end
|
|
26
|
-
|
|
30
|
+
|
|
27
31
|
def inspect
|
|
28
32
|
"#<#{self.class} #{to_s}>"
|
|
29
33
|
end
|
|
30
|
-
|
|
31
|
-
def
|
|
32
|
-
|
|
34
|
+
|
|
35
|
+
def eql?(other)
|
|
36
|
+
self.class.eql?(other.class) &&
|
|
37
|
+
version == other.version
|
|
33
38
|
end
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
alias_method :==, :eql?
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
# Private
|
|
43
|
+
def segments
|
|
44
|
+
@segments ||= version.scan(SEGMENTS_REGEX)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
user_agent_parsers:
|
|
2
2
|
#### SPECIAL CASES TOP ####
|
|
3
3
|
|
|
4
|
-
# must go before Opera
|
|
5
|
-
- regex: '^(Opera)/(\d+)\.(\d+) \(Nintendo Wii'
|
|
6
|
-
family_replacement: 'Wii'
|
|
7
|
-
|
|
8
4
|
# must go before Firefox to catch SeaMonkey/Camino
|
|
9
5
|
- regex: '(SeaMonkey|Camino)/(\d+)\.(\d+)\.?([ab]?\d+[a-z]*)'
|
|
10
6
|
|
|
@@ -66,16 +62,16 @@ user_agent_parsers:
|
|
|
66
62
|
- regex: '(Opera)/9.80.*Version/(\d+)\.(\d+)(?:\.(\d+))?'
|
|
67
63
|
|
|
68
64
|
# Palm WebOS looks a lot like Safari.
|
|
69
|
-
- regex: '(
|
|
70
|
-
|
|
71
|
-
family_replacement: 'webOSBrowser'
|
|
72
|
-
- regex: '(wOSBrowser).+TouchPad/(\d+)\.(\d+)'
|
|
73
|
-
family_replacement: 'webOS TouchPad'
|
|
65
|
+
- regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
|
|
66
|
+
family_replacement: 'webOS Browser'
|
|
74
67
|
|
|
75
68
|
# LuaKit has no version info.
|
|
76
69
|
# http://luakit.org/projects/luakit/
|
|
77
70
|
- regex: '(luakit)'
|
|
78
71
|
family_replacement: 'LuaKit'
|
|
72
|
+
|
|
73
|
+
# Snowshoe
|
|
74
|
+
- regex: '(Snowshoe)/(\d+)\.(\d+).(\d+)'
|
|
79
75
|
|
|
80
76
|
# Lightning (for Thunderbird)
|
|
81
77
|
# http://www.mozilla.org/projects/calendar/lightning/
|
|
@@ -110,9 +106,6 @@ user_agent_parsers:
|
|
|
110
106
|
# Bots
|
|
111
107
|
- regex: '(YottaaMonitor|BrowserMob|HttpMonitor|YandexBot|Slurp|BingPreview|PagePeeker|ThumbShotsBot|WebThumb|URL2PNG|ZooShot|GomezA|Catchpoint bot|Willow Internet Crawler|Google SketchUp|Read%20Later)'
|
|
112
108
|
|
|
113
|
-
# must go before NetFront below
|
|
114
|
-
- regex: '(Kindle)/(\d+)\.(\d+)'
|
|
115
|
-
|
|
116
109
|
- regex: '(Symphony) (\d+).(\d+)'
|
|
117
110
|
|
|
118
111
|
- regex: '(Minimo)'
|
|
@@ -130,7 +123,11 @@ user_agent_parsers:
|
|
|
130
123
|
family_replacement: 'Chrome Frame'
|
|
131
124
|
|
|
132
125
|
# UC Browser
|
|
133
|
-
- regex: '(
|
|
126
|
+
- regex: '(UCBrowser)[ /](\d+)\.(\d+)\.(\d+)'
|
|
127
|
+
family_replacement: 'UC Browser'
|
|
128
|
+
- regex: '(UC Browser)[ /](\d+)\.(\d+)\.(\d+)'
|
|
129
|
+
- regex: '(UC Browser|UCBrowser|UCWEB)(\d+)\.(\d+)\.(\d+)'
|
|
130
|
+
family_replacement: 'UC Browser'
|
|
134
131
|
|
|
135
132
|
# Tizen Browser (second case included in browser/major.minor regex)
|
|
136
133
|
- regex: '(SLP Browser)/(\d+)\.(\d+)'
|
|
@@ -142,8 +139,10 @@ user_agent_parsers:
|
|
|
142
139
|
# Sogou Explorer 2.X
|
|
143
140
|
- regex: '(SE 2\.X) MetaSr (\d+)\.(\d+)'
|
|
144
141
|
family_replacement: 'Sogou Explorer'
|
|
145
|
-
|
|
146
|
-
# Baidu
|
|
142
|
+
|
|
143
|
+
# Baidu Browsers (desktop spoofs chrome & IE, explorer is mobile)
|
|
144
|
+
- regex: '(baidubrowser)[/\s](\d+)'
|
|
145
|
+
family_replacement: 'Baidu Browser'
|
|
147
146
|
- regex: '(FlyFlow)/(\d+)\.(\d+)'
|
|
148
147
|
family_replacement: 'Baidu Explorer'
|
|
149
148
|
|
|
@@ -159,24 +158,39 @@ user_agent_parsers:
|
|
|
159
158
|
- regex: '(Twitterbot)/(\d+)\.(\d+)'
|
|
160
159
|
family_replacement: 'TwitterBot'
|
|
161
160
|
|
|
161
|
+
# Rackspace Monitoring
|
|
162
|
+
- regex: '(Rackspace Monitoring)/(\d+)\.(\d+)'
|
|
163
|
+
family_replacement: 'RackspaceBot'
|
|
164
|
+
|
|
162
165
|
# PyAMF
|
|
163
166
|
- regex: '(PyAMF)/(\d+)\.(\d+)\.(\d+)'
|
|
164
167
|
|
|
168
|
+
# Yandex Browser
|
|
169
|
+
- regex: '(YaBrowser)/(\d+)\.(\d+)\.(\d+)'
|
|
170
|
+
family_replacement: 'Yandex Browser'
|
|
171
|
+
|
|
172
|
+
# Mail.ru Amigo/Internet Browser (Chromium-based)
|
|
173
|
+
- regex: '(Chrome)/(\d+)\.(\d+)\.(\d+).* MRCHROME'
|
|
174
|
+
family_replacement: 'Mail.ru Chromium Browser'
|
|
175
|
+
|
|
165
176
|
#### END SPECIAL CASES TOP ####
|
|
166
177
|
|
|
167
178
|
#### MAIN CASES - this catches > 50% of all browsers ####
|
|
168
179
|
|
|
169
180
|
# Browser/major_version.minor_version.beta_version
|
|
170
|
-
- regex: '(AdobeAIR|Chromium|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Shiira|Sunrise|Chrome|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|
|
|
181
|
+
- regex: '(AdobeAIR|Chromium|FireWeb|Jasmine|ANTGalio|Midori|Fresco|Lobo|PaleMoon|Maxthon|Lynx|OmniWeb|Dillo|Camino|Demeter|Fluid|Fennec|Shiira|Sunrise|Chrome|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+)'
|
|
171
182
|
|
|
172
183
|
# Browser/major_version.minor_version
|
|
173
|
-
- 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)/(\d+)\.(\d+)'
|
|
184
|
+
- 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+)'
|
|
174
185
|
|
|
175
186
|
# Browser major_version.minor_version.beta_version (space instead of slash)
|
|
176
187
|
- regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)'
|
|
177
188
|
# Browser major_version.minor_version (space instead of slash)
|
|
178
|
-
- regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris
|
|
179
|
-
|
|
189
|
+
- regex: '(iCab|Lunascape|Opera|Android|Jasmine|Polaris) (\d+)\.(\d+)\.?(\d+)?'
|
|
190
|
+
|
|
191
|
+
# Kindle WebKit
|
|
192
|
+
- regex: '(Kindle)/(\d+)\.(\d+)'
|
|
193
|
+
|
|
180
194
|
# weird android UAs
|
|
181
195
|
- regex: '(Android) Donut'
|
|
182
196
|
v1_replacement: '1'
|
|
@@ -215,18 +229,32 @@ user_agent_parsers:
|
|
|
215
229
|
- regex: '(Obigo)InternetBrowser'
|
|
216
230
|
- regex: '(Obigo)\-Browser'
|
|
217
231
|
- regex: '(Obigo|OBIGO)[^\d]*(\d+)(?:.(\d+))?'
|
|
232
|
+
family_replacement: 'Obigo'
|
|
218
233
|
|
|
219
234
|
- regex: '(MAXTHON|Maxthon) (\d+)\.(\d+)'
|
|
220
235
|
family_replacement: 'Maxthon'
|
|
221
236
|
- regex: '(Maxthon|MyIE2|Uzbl|Shiira)'
|
|
222
237
|
v1_replacement: '0'
|
|
223
238
|
|
|
224
|
-
- regex: '
|
|
225
|
-
family_replacement: '
|
|
226
|
-
- regex: '
|
|
239
|
+
- regex: 'PLAYSTATION 3.+WebKit'
|
|
240
|
+
family_replacement: 'NetFront NX'
|
|
241
|
+
- regex: 'PLAYSTATION 3'
|
|
242
|
+
family_replacement: 'NetFront'
|
|
243
|
+
- regex: '(PlayStation Portable)'
|
|
244
|
+
family_replacement: 'NetFront'
|
|
245
|
+
- regex: '(PlayStation Vita)'
|
|
246
|
+
family_replacement: 'NetFront NX'
|
|
247
|
+
|
|
248
|
+
- regex: 'AppleWebKit.+ (NX)/(\d+)\.(\d+)\.(\d+)'
|
|
249
|
+
family_replacement: 'NetFront NX'
|
|
250
|
+
- regex: '(Nintendo 3DS)'
|
|
251
|
+
family_replacement: 'NetFront NX'
|
|
227
252
|
|
|
228
253
|
- regex: '(BrowseX) \((\d+)\.(\d+)\.(\d+)'
|
|
229
254
|
|
|
255
|
+
- regex: '(NCSA_Mosaic)/(\d+)\.(\d+)'
|
|
256
|
+
family_replacement: 'NCSA Mosaic'
|
|
257
|
+
|
|
230
258
|
# Polaris/d.d is above
|
|
231
259
|
- regex: '(POLARIS)/(\d+)\.(\d+)'
|
|
232
260
|
family_replacement: 'Polaris'
|
|
@@ -236,6 +264,9 @@ user_agent_parsers:
|
|
|
236
264
|
- regex: '(BonEcho)/(\d+)\.(\d+)\.(\d+)'
|
|
237
265
|
family_replacement: 'Bon Echo'
|
|
238
266
|
|
|
267
|
+
- regex: 'M?QQBrowser'
|
|
268
|
+
family_replacement: 'QQ Browser'
|
|
269
|
+
|
|
239
270
|
- regex: '(iPod).+Version/(\d+)\.(\d+)\.(\d+)'
|
|
240
271
|
family_replacement: 'Mobile Safari'
|
|
241
272
|
- regex: '(iPod).*Version/(\d+)\.(\d+)'
|
|
@@ -254,36 +285,50 @@ user_agent_parsers:
|
|
|
254
285
|
family_replacement: 'Mobile Safari'
|
|
255
286
|
|
|
256
287
|
- regex: '(AvantGo) (\d+).(\d+)'
|
|
288
|
+
|
|
289
|
+
- regex: '(OneBrowser)/(\d+).(\d+)'
|
|
290
|
+
family_replacement: 'ONE Browser'
|
|
257
291
|
|
|
258
292
|
- regex: '(Avant)'
|
|
259
293
|
v1_replacement: '1'
|
|
260
294
|
|
|
295
|
+
# This is the Tesla Model S (see similar entry in device parsers)
|
|
296
|
+
- regex: '(QtCarBrowser)'
|
|
297
|
+
v1_replacement: '1'
|
|
298
|
+
|
|
299
|
+
- regex: '(iBrowser/Mini)(\d+).(\d+)'
|
|
300
|
+
family_replacement: 'iBrowser Mini'
|
|
261
301
|
# nokia browsers
|
|
262
302
|
# based on: http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices
|
|
263
303
|
- regex: '^(Nokia)'
|
|
264
304
|
family_replacement: 'Nokia Services (WAP) Browser'
|
|
265
305
|
- regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)\.(\d+)'
|
|
306
|
+
family_replacement: 'Nokia Browser'
|
|
266
307
|
- regex: '(NokiaBrowser)/(\d+)\.(\d+).(\d+)'
|
|
308
|
+
family_replacement: 'Nokia Browser'
|
|
267
309
|
- regex: '(NokiaBrowser)/(\d+)\.(\d+)'
|
|
310
|
+
family_replacement: 'Nokia Browser'
|
|
268
311
|
- regex: '(BrowserNG)/(\d+)\.(\d+).(\d+)'
|
|
269
|
-
family_replacement: '
|
|
312
|
+
family_replacement: 'Nokia Browser'
|
|
270
313
|
- regex: '(Series60)/5\.0'
|
|
271
|
-
family_replacement: '
|
|
314
|
+
family_replacement: 'Nokia Browser'
|
|
272
315
|
v1_replacement: '7'
|
|
273
316
|
v2_replacement: '0'
|
|
274
317
|
- regex: '(Series60)/(\d+)\.(\d+)'
|
|
275
318
|
family_replacement: 'Nokia OSS Browser'
|
|
276
319
|
- regex: '(S40OviBrowser)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
|
|
277
|
-
family_replacement: '
|
|
320
|
+
family_replacement: 'Ovi Browser'
|
|
278
321
|
- regex: '(Nokia)[EN]?(\d+)'
|
|
279
322
|
|
|
280
323
|
# BlackBerry devices
|
|
324
|
+
- regex: '(BB10);'
|
|
325
|
+
family_replacement: 'BlackBerry WebKit'
|
|
281
326
|
- regex: '(PlayBook).+RIM Tablet OS (\d+)\.(\d+)\.(\d+)'
|
|
282
|
-
family_replacement: '
|
|
327
|
+
family_replacement: 'BlackBerry WebKit'
|
|
283
328
|
- regex: '(Black[bB]erry).+Version/(\d+)\.(\d+)\.(\d+)'
|
|
284
|
-
family_replacement: '
|
|
329
|
+
family_replacement: 'BlackBerry WebKit'
|
|
285
330
|
- regex: '(Black[bB]erry)\s?(\d+)'
|
|
286
|
-
family_replacement: '
|
|
331
|
+
family_replacement: 'BlackBerry'
|
|
287
332
|
|
|
288
333
|
- regex: '(OmniWeb)/v(\d+)\.(\d+)'
|
|
289
334
|
|
|
@@ -302,6 +347,7 @@ user_agent_parsers:
|
|
|
302
347
|
|
|
303
348
|
# Amazon Silk, should go before Safari
|
|
304
349
|
- regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
|
|
350
|
+
family_replacement: 'Amazon Silk'
|
|
305
351
|
|
|
306
352
|
# WebKit Nightly
|
|
307
353
|
- regex: '(AppleWebKit)/(\d+)\.?(\d+)?\+ .* Safari'
|
|
@@ -322,11 +368,15 @@ user_agent_parsers:
|
|
|
322
368
|
|
|
323
369
|
- regex: '(Teleca)'
|
|
324
370
|
family_replacement: 'Teleca Browser'
|
|
371
|
+
|
|
372
|
+
- regex: '(Phantom)/V(\d+)\.(\d+)'
|
|
373
|
+
family_replacement: 'Phantom Browser'
|
|
325
374
|
|
|
326
375
|
- regex: '(MSIE) (\d+)\.(\d+)'
|
|
327
376
|
family_replacement: 'IE'
|
|
328
377
|
|
|
329
|
-
- regex: '(
|
|
378
|
+
- regex: '(python-requests)/(\d+)\.(\d+)'
|
|
379
|
+
family_replacement: 'Python Requests'
|
|
330
380
|
|
|
331
381
|
os_parsers:
|
|
332
382
|
|
|
@@ -356,6 +406,12 @@ os_parsers:
|
|
|
356
406
|
- regex: '(Android) Honeycomb'
|
|
357
407
|
os_v1_replacement: '3'
|
|
358
408
|
|
|
409
|
+
##########
|
|
410
|
+
# Kindle Android
|
|
411
|
+
##########
|
|
412
|
+
- regex: '(Silk-Accelerated=[a-z]{4,5})'
|
|
413
|
+
os_replacement: 'Android'
|
|
414
|
+
|
|
359
415
|
##########
|
|
360
416
|
# Windows
|
|
361
417
|
# http://en.wikipedia.org/wiki/Windows_NT#Releases
|
|
@@ -364,15 +420,14 @@ os_parsers:
|
|
|
364
420
|
# lots of ua strings have Windows NT 4.1 !?!?!?!? !?!? !? !????!?! !!! ??? !?!?! ?
|
|
365
421
|
# (very) roughly ordered in terms of frequency of occurence of regex (win xp currently most frequent, etc)
|
|
366
422
|
##########
|
|
367
|
-
|
|
368
|
-
|
|
423
|
+
|
|
369
424
|
- regex: '(Windows (?:NT 5\.2|NT 5\.1))'
|
|
370
425
|
os_replacement: 'Windows XP'
|
|
371
426
|
|
|
372
427
|
# ie mobile des ktop mode
|
|
373
428
|
# spoofs nt 6.1. must come before windows 7
|
|
374
429
|
- regex: '(XBLWP7)'
|
|
375
|
-
os_replacement: 'Windows Phone
|
|
430
|
+
os_replacement: 'Windows Phone'
|
|
376
431
|
|
|
377
432
|
- regex: '(Windows NT 6\.1)'
|
|
378
433
|
os_replacement: 'Windows 7'
|
|
@@ -380,7 +435,10 @@ os_parsers:
|
|
|
380
435
|
- regex: '(Windows NT 6\.0)'
|
|
381
436
|
os_replacement: 'Windows Vista'
|
|
382
437
|
|
|
383
|
-
- regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000)'
|
|
438
|
+
- regex: '(Windows 98|Windows XP|Windows ME|Windows 95|Windows CE|Windows 7|Windows NT 4\.0|Windows Vista|Windows 2000|Windows 3.1)'
|
|
439
|
+
|
|
440
|
+
- regex: '(Windows NT 6\.2; ARM;)'
|
|
441
|
+
os_replacement: 'Windows RT'
|
|
384
442
|
|
|
385
443
|
# is this a spoof or is nt 6.2 out and about in some capacity?
|
|
386
444
|
- regex: '(Windows NT 6\.2)'
|
|
@@ -389,8 +447,8 @@ os_parsers:
|
|
|
389
447
|
- regex: '(Windows NT 5\.0)'
|
|
390
448
|
os_replacement: 'Windows 2000'
|
|
391
449
|
|
|
392
|
-
- regex: '(Windows Phone
|
|
393
|
-
|
|
450
|
+
- regex: '(Windows Phone) (\d+)\.(\d+)'
|
|
451
|
+
- regex: '(Windows Phone) OS (\d+)\.(\d+)'
|
|
394
452
|
- regex: '(Windows ?Mobile)'
|
|
395
453
|
os_replacement: 'Windows Mobile'
|
|
396
454
|
|
|
@@ -406,13 +464,15 @@ os_parsers:
|
|
|
406
464
|
##########
|
|
407
465
|
- regex: '(Tizen)/(\d+)\.(\d+)'
|
|
408
466
|
|
|
409
|
-
|
|
410
|
-
|
|
411
467
|
##########
|
|
412
468
|
# Mac OS
|
|
413
469
|
# http://en.wikipedia.org/wiki/Mac_OS_X#Versions
|
|
414
470
|
##########
|
|
415
471
|
- regex: '(Mac OS X) (\d+)[_.](\d+)(?:[_.](\d+))?'
|
|
472
|
+
|
|
473
|
+
# IE on Mac doesn't specify version number
|
|
474
|
+
- regex: 'Mac_PowerPC'
|
|
475
|
+
os_replacement: 'Mac OS'
|
|
416
476
|
|
|
417
477
|
# builds before tiger don't seem to specify version?
|
|
418
478
|
|
|
@@ -472,10 +532,14 @@ os_parsers:
|
|
|
472
532
|
- regex: '(MeeGo)'
|
|
473
533
|
- regex: 'Symbian [Oo][Ss]'
|
|
474
534
|
os_replacement: 'Symbian OS'
|
|
535
|
+
- regex: 'Series40;'
|
|
536
|
+
os_replacement: 'Nokia Series 40'
|
|
475
537
|
|
|
476
538
|
##########
|
|
477
539
|
# BlackBerry devices
|
|
478
540
|
##########
|
|
541
|
+
- regex: '(BB10);.+Version/(\d+)\.(\d+)\.(\d+)'
|
|
542
|
+
os_replacement: 'BlackBerry OS'
|
|
479
543
|
- regex: '(Black[Bb]erry)[0-9a-z]+/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
|
|
480
544
|
os_replacement: 'BlackBerry OS'
|
|
481
545
|
- regex: '(Black[Bb]erry).+Version/(\d+)\.(\d+)\.(\d+)(?:\.(\d+))?'
|
|
@@ -485,7 +549,24 @@ os_parsers:
|
|
|
485
549
|
- regex: '(Play[Bb]ook)'
|
|
486
550
|
os_replacement: 'BlackBerry Tablet OS'
|
|
487
551
|
- regex: '(Black[Bb]erry)'
|
|
488
|
-
os_replacement: '
|
|
552
|
+
os_replacement: 'BlackBerry OS'
|
|
553
|
+
|
|
554
|
+
##########
|
|
555
|
+
# Firefox OS
|
|
556
|
+
##########
|
|
557
|
+
- regex: '\(Mobile;.+Firefox/\d+\.\d+'
|
|
558
|
+
os_replacement: 'Firefox OS'
|
|
559
|
+
|
|
560
|
+
##########
|
|
561
|
+
# BREW
|
|
562
|
+
# yes, Brew is lower-cased for Brew MP
|
|
563
|
+
##########
|
|
564
|
+
- regex: '(BREW)[ /](\d+)\.(\d+)\.(\d+)'
|
|
565
|
+
- regex: '(BREW);'
|
|
566
|
+
- regex: '(Brew MP|BMP)[ /](\d+)\.(\d+)\.(\d+)'
|
|
567
|
+
os_replacement: 'Brew MP'
|
|
568
|
+
- regex: 'BMP;'
|
|
569
|
+
os_replacement: 'Brew MP'
|
|
489
570
|
|
|
490
571
|
##########
|
|
491
572
|
# Google TV
|
|
@@ -494,11 +575,14 @@ os_parsers:
|
|
|
494
575
|
# Old style
|
|
495
576
|
- regex: '(GoogleTV)\/\d+'
|
|
496
577
|
|
|
578
|
+
- regex: '(WebTV)/(\d+).(\d+)'
|
|
579
|
+
|
|
497
580
|
##########
|
|
498
581
|
# Misc mobile
|
|
499
582
|
##########
|
|
500
|
-
- regex: '(
|
|
583
|
+
- regex: '(hpw|web)OS/(\d+)\.(\d+)(?:\.(\d+))?'
|
|
501
584
|
os_replacement: 'webOS'
|
|
585
|
+
- regex: '(VRE);'
|
|
502
586
|
|
|
503
587
|
##########
|
|
504
588
|
# Generic patterns
|
|
@@ -512,11 +596,13 @@ os_parsers:
|
|
|
512
596
|
|
|
513
597
|
# first.second bits
|
|
514
598
|
- regex: '(Ubuntu|Kindle|Bada|Lubuntu|BackTrack|Red Hat|Slackware)/(\d+)\.(\d+)'
|
|
515
|
-
- regex: '(PlayStation Vita) (\d+)\.(\d+)'
|
|
516
599
|
|
|
517
600
|
# just os
|
|
518
601
|
- regex: '(Windows|OpenBSD|FreeBSD|NetBSD|Ubuntu|Kubuntu|Android|Arch Linux|CentOS|WeTab|Slackware)'
|
|
602
|
+
- regex: '(Linux)/(\d+)\.(\d+)'
|
|
519
603
|
- regex: '(Linux|BSD)'
|
|
604
|
+
- regex: 'SunOS'
|
|
605
|
+
os_replacement: 'Solaris'
|
|
520
606
|
|
|
521
607
|
device_parsers:
|
|
522
608
|
##########
|
|
@@ -547,16 +633,16 @@ device_parsers:
|
|
|
547
633
|
device_replacement: 'HTC $1 (Sprint)'
|
|
548
634
|
- regex: 'HTC ([A-Za-z0-9]+ [A-Z])'
|
|
549
635
|
device_replacement: 'HTC $1'
|
|
550
|
-
- regex: 'HTC-([A-Za-z0-9]+)'
|
|
551
|
-
device_replacement: 'HTC $1'
|
|
552
|
-
- regex: 'HTC_([A-Za-z0-9]+)'
|
|
553
|
-
device_replacement: 'HTC $1'
|
|
554
|
-
- regex: 'HTC ([A-Za-z0-9]+)'
|
|
636
|
+
- regex: 'HTC[-_/\s]([A-Za-z0-9]+)'
|
|
555
637
|
device_replacement: 'HTC $1'
|
|
556
638
|
- regex: '(ADR[A-Za-z0-9]+)'
|
|
557
639
|
device_replacement: 'HTC $1'
|
|
558
640
|
- regex: '(HTC)'
|
|
559
641
|
|
|
642
|
+
# Tesla Model S
|
|
643
|
+
- regex: '(QtCarBrowser)'
|
|
644
|
+
device_replacement: 'Tesla Model S'
|
|
645
|
+
|
|
560
646
|
# Samsung
|
|
561
647
|
- regex: '(SamsungSGHi560)'
|
|
562
648
|
device_replacement: 'Samsung SGHi560'
|
|
@@ -567,14 +653,43 @@ device_parsers:
|
|
|
567
653
|
- regex: 'SonyEricsson([A-Za-z0-9]+)/'
|
|
568
654
|
device_replacement: 'Ericsson $1'
|
|
569
655
|
|
|
656
|
+
##########
|
|
657
|
+
# PlayStation
|
|
658
|
+
# The Vita spoofs the Kindle
|
|
659
|
+
##########
|
|
660
|
+
- regex: 'PLAYSTATION 3'
|
|
661
|
+
device_replacement: 'PlayStation 3'
|
|
662
|
+
- regex: '(PlayStation Portable)'
|
|
663
|
+
- regex: '(PlayStation Vita)'
|
|
664
|
+
|
|
665
|
+
##########
|
|
666
|
+
# incomplete!
|
|
667
|
+
# Kindle
|
|
668
|
+
# http://amazonsilk.wordpress.com/useful-bits/silk-user-agent/
|
|
669
|
+
##########
|
|
670
|
+
- regex: '(KFOT Build)'
|
|
671
|
+
device_replacement: 'Kindle Fire'
|
|
672
|
+
- regex: '(KFTT Build)'
|
|
673
|
+
device_replacement: 'Kindle Fire HD'
|
|
674
|
+
- regex: '(KFJWI Build)'
|
|
675
|
+
device_replacement: 'Kindle Fire HD 8.9" WiFi'
|
|
676
|
+
- regex: '(KFJWA Build)'
|
|
677
|
+
device_replacement: 'Kindle Fire HD 8.9" 4G'
|
|
678
|
+
- regex: '(Kindle Fire)'
|
|
679
|
+
- regex: '(Kindle)'
|
|
680
|
+
- regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
|
|
681
|
+
device_replacement: 'Kindle Fire'
|
|
682
|
+
|
|
570
683
|
#########
|
|
571
684
|
# Android General Device Matching (far from perfect)
|
|
572
685
|
#########
|
|
573
|
-
- regex: 'Android[\- ][\d]+\.[\d]
|
|
574
|
-
- regex: 'Android[\- ][\d]+\.[\d]
|
|
575
|
-
- regex: 'Android[\- ][\d]+\.[\d]
|
|
576
|
-
- regex: 'Android[\- ][\d]+\.[\d]
|
|
686
|
+
- regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{2}; WOWMobile (.+) Build'
|
|
687
|
+
- regex: 'Android[\- ][\d]+\.[\d]+\-update1; [A-Za-z]{2}\-[A-Za-z]{2}; (.+) Build'
|
|
688
|
+
- regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{2}; (.+) Build'
|
|
689
|
+
- regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+;[A-Za-z]{2}\-[A-Za-z]{2};(.+) Build'
|
|
690
|
+
- regex: 'Android[\- ][\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{2}; (.+) Build'
|
|
577
691
|
- regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; (.+) Build'
|
|
692
|
+
- regex: 'Android[\- ][\d]+\.[\d]+; (.+) Build'
|
|
578
693
|
|
|
579
694
|
##########
|
|
580
695
|
# NOKIA
|
|
@@ -582,6 +697,8 @@ device_parsers:
|
|
|
582
697
|
##########
|
|
583
698
|
- regex: 'NokiaN([0-9]+)'
|
|
584
699
|
device_replacement: 'Nokia N$1'
|
|
700
|
+
- regex: 'NOKIA([A-Za-z0-9\v-]+)'
|
|
701
|
+
device_replacement: 'Nokia $1'
|
|
585
702
|
- regex: 'Nokia([A-Za-z0-9\v-]+)'
|
|
586
703
|
device_replacement: 'Nokia $1'
|
|
587
704
|
- regex: 'NOKIA ([A-Za-z0-9\-]+)'
|
|
@@ -594,14 +711,19 @@ device_parsers:
|
|
|
594
711
|
device_replacement: 'Nokia'
|
|
595
712
|
|
|
596
713
|
##########
|
|
597
|
-
#
|
|
714
|
+
# BlackBerry
|
|
598
715
|
# http://www.useragentstring.com/pages/BlackBerry/
|
|
599
716
|
##########
|
|
717
|
+
- regex: 'BB10; ([A-Za-z0-9\- ]+)\)'
|
|
718
|
+
device_replacement: 'BlackBerry $1'
|
|
600
719
|
- regex: '(PlayBook).+RIM Tablet OS'
|
|
601
|
-
device_replacement: '
|
|
602
|
-
- regex: '
|
|
720
|
+
device_replacement: 'BlackBerry Playbook'
|
|
721
|
+
- regex: 'Black[Bb]erry ([0-9]+);'
|
|
722
|
+
device_replacement: 'BlackBerry $1'
|
|
603
723
|
- regex: 'Black[Bb]erry([0-9]+)'
|
|
604
724
|
device_replacement: 'BlackBerry $1'
|
|
725
|
+
- regex: 'Black[Bb]erry;'
|
|
726
|
+
device_replacement: 'BlackBerry'
|
|
605
727
|
|
|
606
728
|
##########
|
|
607
729
|
# PALM / HP
|
|
@@ -611,8 +733,8 @@ device_parsers:
|
|
|
611
733
|
device_replacement: 'Palm Pre'
|
|
612
734
|
- regex: '(Pixi)/(\d+)\.(\d+)'
|
|
613
735
|
device_replacement: 'Palm Pixi'
|
|
614
|
-
- regex: '(
|
|
615
|
-
device_replacement: 'HP
|
|
736
|
+
- regex: '(Touch[Pp]ad)/(\d+)\.(\d+)'
|
|
737
|
+
device_replacement: 'HP TouchPad'
|
|
616
738
|
- regex: 'HPiPAQ([A-Za-z0-9]+)/(\d+).(\d+)'
|
|
617
739
|
device_replacement: 'HP iPAQ $1'
|
|
618
740
|
- regex: 'Palm([A-Za-z0-9]+)'
|
|
@@ -622,21 +744,6 @@ device_parsers:
|
|
|
622
744
|
- regex: 'webOS.*(P160UNA)/(\d+).(\d+)'
|
|
623
745
|
device_replacement: 'HP Veer'
|
|
624
746
|
|
|
625
|
-
##########
|
|
626
|
-
# PlayStation
|
|
627
|
-
##########
|
|
628
|
-
- regex: '(PlayStation Portable)'
|
|
629
|
-
- regex: '(PlayStation Vita)'
|
|
630
|
-
|
|
631
|
-
##########
|
|
632
|
-
# incomplete!
|
|
633
|
-
# Kindle
|
|
634
|
-
##########
|
|
635
|
-
- regex: '(Kindle Fire)'
|
|
636
|
-
- regex: '(Kindle)'
|
|
637
|
-
- regex: '(Silk)/(\d+)\.(\d+)(?:\.([0-9\-]+))?'
|
|
638
|
-
device_replacement: 'Kindle Fire'
|
|
639
|
-
|
|
640
747
|
##########
|
|
641
748
|
# AppleTV
|
|
642
749
|
# No built in browser that I can tell
|
|
@@ -665,6 +772,14 @@ device_parsers:
|
|
|
665
772
|
- regex: 'acer_([A-Za-z0-9]+)_'
|
|
666
773
|
device_replacement: 'Acer $1'
|
|
667
774
|
|
|
775
|
+
##########
|
|
776
|
+
# Alcatel
|
|
777
|
+
##########
|
|
778
|
+
- regex: 'ALCATEL-([A-Za-z0-9]+)'
|
|
779
|
+
device_replacement: 'Alcatel $1'
|
|
780
|
+
- regex: 'Alcatel-([A-Za-z0-9]+)'
|
|
781
|
+
device_replacement: 'Alcatel $1'
|
|
782
|
+
|
|
668
783
|
##########
|
|
669
784
|
# Amoi
|
|
670
785
|
##########
|
|
@@ -702,14 +817,18 @@ device_parsers:
|
|
|
702
817
|
##########
|
|
703
818
|
- regex: 'DoCoMo/2\.0 ([A-Za-z0-9]+)'
|
|
704
819
|
device_replacement: 'DoCoMo $1'
|
|
705
|
-
- regex: '([A-Za-z0-9]+)
|
|
820
|
+
- regex: '([A-Za-z0-9]+)_W\;FOMA'
|
|
706
821
|
device_replacement: 'DoCoMo $1'
|
|
707
822
|
- regex: '([A-Za-z0-9]+)\;FOMA'
|
|
708
823
|
device_replacement: 'DoCoMo $1'
|
|
709
824
|
|
|
710
825
|
##########
|
|
711
|
-
# Huawei
|
|
826
|
+
# Huawei
|
|
712
827
|
##########
|
|
828
|
+
- regex: 'Huawei([A-Za-z0-9]+)'
|
|
829
|
+
device_replacement: 'Huawei $1'
|
|
830
|
+
- regex: 'HUAWEI-([A-Za-z0-9]+)'
|
|
831
|
+
device_replacement: 'Huawei $1'
|
|
713
832
|
- regex: 'vodafone([A-Za-z0-9]+)'
|
|
714
833
|
device_replacement: 'Huawei Vodafone $1'
|
|
715
834
|
|
|
@@ -732,7 +851,7 @@ device_parsers:
|
|
|
732
851
|
##########
|
|
733
852
|
- regex: 'Lenovo\-([A-Za-z0-9]+)'
|
|
734
853
|
device_replacement: 'Lenovo $1'
|
|
735
|
-
- regex: '
|
|
854
|
+
- regex: 'Lenovo_([A-Za-z0-9]+)'
|
|
736
855
|
device_replacement: 'Lenovo $1'
|
|
737
856
|
|
|
738
857
|
##########
|
|
@@ -773,7 +892,21 @@ device_parsers:
|
|
|
773
892
|
device_replacement: 'Motorola $1'
|
|
774
893
|
- regex: 'MOT\-([A-Za-z0-9]+)'
|
|
775
894
|
device_replacement: 'Motorola $1'
|
|
895
|
+
|
|
896
|
+
##########
|
|
897
|
+
# nintendo
|
|
898
|
+
##########
|
|
899
|
+
- regex: '(Nintendo WiiU)'
|
|
900
|
+
device_replacement: 'Nintendo Wii U'
|
|
901
|
+
- regex: 'Nintendo (DS|3DS|DSi|Wii);'
|
|
902
|
+
device_replacement: 'Nintendo $1'
|
|
776
903
|
|
|
904
|
+
##########
|
|
905
|
+
# pantech
|
|
906
|
+
##########
|
|
907
|
+
- regex: 'Pantech([A-Za-z0-9]+)'
|
|
908
|
+
device_replacement: 'Pantech $1'
|
|
909
|
+
|
|
777
910
|
##########
|
|
778
911
|
# philips
|
|
779
912
|
##########
|
|
@@ -790,6 +923,12 @@ device_parsers:
|
|
|
790
923
|
- regex: 'SAMSUNG\; ([A-Za-z0-9\-]+)'
|
|
791
924
|
device_replacement: 'Samsung $1'
|
|
792
925
|
|
|
926
|
+
##########
|
|
927
|
+
# Sega
|
|
928
|
+
##########
|
|
929
|
+
- regex: 'Dreamcast'
|
|
930
|
+
device_replacement: 'Sega Dreamcast'
|
|
931
|
+
|
|
793
932
|
##########
|
|
794
933
|
# Softbank
|
|
795
934
|
##########
|
|
@@ -799,10 +938,9 @@ device_parsers:
|
|
|
799
938
|
device_replacement: 'Softbank $1'
|
|
800
939
|
|
|
801
940
|
##########
|
|
802
|
-
#
|
|
941
|
+
# WebTV
|
|
803
942
|
##########
|
|
804
|
-
- regex: '(
|
|
805
|
-
device_replacement: 'Playstation 3'
|
|
943
|
+
- regex: '(WebTV)/(\d+).(\d+)'
|
|
806
944
|
|
|
807
945
|
##########
|
|
808
946
|
# Generic Smart Phone
|
|
@@ -813,13 +951,13 @@ device_parsers:
|
|
|
813
951
|
##########
|
|
814
952
|
# Generic Feature Phone
|
|
815
953
|
##########
|
|
816
|
-
- regex: '^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\-|airn|alav|asus|attw|au\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\-n|bw\-u|beck|benq|bilb|blac|c55/|cdm\-|chtm|capi|comp|cond|craw|dall|dbte|dc\-s|dica|ds\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\-|
|
|
954
|
+
- regex: '^(1207|3gso|4thp|501i|502i|503i|504i|505i|506i|6310|6590|770s|802s|a wa|acer|acs\-|airn|alav|asus|attw|au\-m|aur |aus |abac|acoo|aiko|alco|alca|amoi|anex|anny|anyw|aptu|arch|argo|bell|bird|bw\-n|bw\-u|beck|benq|bilb|blac|c55/|cdm\-|chtm|capi|comp|cond|craw|dall|dbte|dc\-s|dica|ds\-d|ds12|dait|devi|dmob|doco|dopo|el49|erk0|esl8|ez40|ez60|ez70|ezos|ezze|elai|emul|eric|ezwa|fake|fly\-|fly_|g\-mo|g1 u|g560|gf\-5|grun|gene|go.w|good|grad|hcit|hd\-m|hd\-p|hd\-t|hei\-|hp i|hpip|hs\-c|htc |htc\-|htca|htcg)'
|
|
817
955
|
device_replacement: 'Generic Feature Phone'
|
|
818
|
-
- regex: '^(htcp|htcs|htct|
|
|
956
|
+
- regex: '^(htcp|htcs|htct|htc_|haie|hita|huaw|hutc|i\-20|i\-go|i\-ma|i230|iac|iac\-|iac/|ig01|im1k|inno|iris|jata|java|kddi|kgt|kgt/|kpt |kwc\-|klon|lexi|lg g|lg\-a|lg\-b|lg\-c|lg\-d|lg\-f|lg\-g|lg\-k|lg\-l|lg\-m|lg\-o|lg\-p|lg\-s|lg\-t|lg\-u|lg\-w|lg/k|lg/l|lg/u|lg50|lg54|lge\-|lge/|lynx|leno|m1\-w|m3ga|m50/|maui|mc01|mc21|mcca|medi|meri|mio8|mioa|mo01|mo02|mode|modo|mot |mot\-|mt50|mtp1|mtv |mate|maxo|merc|mits|mobi|motv|mozz|n100|n101|n102|n202|n203|n300|n302|n500|n502|n505|n700|n701|n710|nec\-|nem\-|newg|neon)'
|
|
819
957
|
device_replacement: 'Generic Feature Phone'
|
|
820
958
|
- regex: '^(netf|noki|nzph|o2 x|o2\-x|opwv|owg1|opti|oran|ot\-s|p800|pand|pg\-1|pg\-2|pg\-3|pg\-6|pg\-8|pg\-c|pg13|phil|pn\-2|pt\-g|palm|pana|pire|pock|pose|psio|qa\-a|qc\-2|qc\-3|qc\-5|qc\-7|qc07|qc12|qc21|qc32|qc60|qci\-|qwap|qtek|r380|r600|raks|rim9|rove|s55/|sage|sams|sc01|sch\-|scp\-|sdk/|se47|sec\-|sec0|sec1|semc|sgh\-|shar|sie\-|sk\-0|sl45|slid|smb3|smt5|sp01|sph\-|spv |spv\-|sy01|samm|sany|sava|scoo|send|siem|smar|smit|soft|sony|t\-mo|t218|t250|t600|t610|t618|tcl\-|tdg\-|telm|tim\-|ts70|tsm\-|tsm3|tsm5|tx\-9|tagt)'
|
|
821
959
|
device_replacement: 'Generic Feature Phone'
|
|
822
|
-
- regex: '^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\-|your|zte\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\-|webc|whit|wmlb|xda\-|
|
|
960
|
+
- regex: '^(talk|teli|topl|tosh|up.b|upg1|utst|v400|v750|veri|vk\-v|vk40|vk50|vk52|vk53|vm40|vx98|virg|vite|voda|vulc|w3c |w3c\-|wapj|wapp|wapu|wapm|wig |wapi|wapr|wapv|wapy|wapa|waps|wapt|winc|winw|wonu|x700|xda2|xdag|yas\-|your|zte\-|zeto|aste|audi|avan|blaz|brew|brvw|bumb|ccwa|cell|cldc|cmd\-|dang|eml2|fetc|hipt|http|ibro|idea|ikom|ipaq|jbro|jemu|jigs|keji|kyoc|kyok|libw|m\-cr|midp|mmef|moto|mwbp|mywa|newt|nok6|o2im|pant|pdxg|play|pluc|port|prox|rozo|sama|seri|smal|symb|treo|upsi|vx52|vx53|vx60|vx61|vx70|vx80|vx81|vx83|vx85|wap\-|webc|whit|wmlb|xda\-|xda_)'
|
|
823
961
|
device_replacement: 'Generic Feature Phone'
|
|
824
962
|
|
|
825
963
|
##########
|
|
@@ -828,43 +966,3 @@ device_parsers:
|
|
|
828
966
|
- 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)'
|
|
829
967
|
device_replacement: 'Spider'
|
|
830
968
|
|
|
831
|
-
|
|
832
|
-
mobile_user_agent_families:
|
|
833
|
-
- 'Firefox Mobile'
|
|
834
|
-
- 'Opera Mobile'
|
|
835
|
-
- 'Opera Mini'
|
|
836
|
-
- 'Mobile Safari'
|
|
837
|
-
- 'webOS'
|
|
838
|
-
- 'IE Mobile'
|
|
839
|
-
- 'Playstation Portable'
|
|
840
|
-
- 'Nokia'
|
|
841
|
-
- 'Blackberry'
|
|
842
|
-
- 'Palm'
|
|
843
|
-
- 'Silk'
|
|
844
|
-
- 'Android'
|
|
845
|
-
- 'Maemo'
|
|
846
|
-
- 'Obigo'
|
|
847
|
-
- 'Netfront'
|
|
848
|
-
- 'AvantGo'
|
|
849
|
-
- 'Teleca'
|
|
850
|
-
- 'SEMC-Browser'
|
|
851
|
-
- 'Bolt'
|
|
852
|
-
- 'Iris'
|
|
853
|
-
- 'UP.Browser'
|
|
854
|
-
- 'Symphony'
|
|
855
|
-
- 'Minimo'
|
|
856
|
-
- 'Bunjaloo'
|
|
857
|
-
- 'Jasmine'
|
|
858
|
-
- 'Dolfin'
|
|
859
|
-
- 'Polaris'
|
|
860
|
-
- 'BREW'
|
|
861
|
-
- 'Chrome Mobile'
|
|
862
|
-
- 'UC Browser'
|
|
863
|
-
- 'Tizen Browser'
|
|
864
|
-
|
|
865
|
-
# Some select mobile OSs report a desktop browser.
|
|
866
|
-
# make sure we note they're mobile
|
|
867
|
-
mobile_os_families:
|
|
868
|
-
- 'Windows Phone 6.5'
|
|
869
|
-
- 'Windows CE'
|
|
870
|
-
- 'Symbian OS'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: user_agent_parser
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2013-02-18 00:00:00.000000000 Z
|
|
13
13
|
dependencies: []
|
|
14
14
|
description: A simple, comprehensive Ruby gem for parsing user agent strings with
|
|
15
15
|
the help of BrowserScope's UA database
|
|
@@ -21,6 +21,7 @@ files:
|
|
|
21
21
|
- MIT-LICENSE
|
|
22
22
|
- Readme.md
|
|
23
23
|
- lib/user_agent_parser.rb
|
|
24
|
+
- lib/user_agent_parser/device.rb
|
|
24
25
|
- lib/user_agent_parser/operating_system.rb
|
|
25
26
|
- lib/user_agent_parser/parser.rb
|
|
26
27
|
- lib/user_agent_parser/user_agent.rb
|
|
@@ -38,7 +39,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
38
39
|
requirements:
|
|
39
40
|
- - ! '>='
|
|
40
41
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: 1.
|
|
42
|
+
version: 1.8.7
|
|
42
43
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
43
44
|
none: false
|
|
44
45
|
requirements:
|