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 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.9.2
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
- ua = UserAgentParser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
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
- ua.to_s
22
+ user_agent.to_s
25
23
  => "IE 9.0"
26
- ua.family
24
+ user_agent.name
27
25
  => "IE"
28
- ua.version.to_s
26
+ user_agent.version.to_s
29
27
  => "9.0"
30
- ua.version.major
31
- => 9
32
- ua.version.minor
33
- => 0
34
- os = ua.os
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
- os.to_s
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 = '/some/path/to/regexes.yaml'
53
+ UserAgentParser.parse(ua_string, patterns_path: '/some/path/to/regexes.yaml')
48
54
  ```
49
55
 
50
- ## Comprehensive you say?
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
- 12836 tests, 33888 assertions, 0 failures, 0 errors, 0 skips
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
@@ -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 user_agent_string
22
- Parser.new.parse user_agent_string
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
- attr_accessor :name, :version
6
-
7
- def initialize(name="Other", version=nil)
8
- self.name = name
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
- s = name
14
- s += " #{version}" if version
15
- s
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 ==(other)
23
- name == other.name && version == other.version
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
- end
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 parse user_agent
8
- ua = parse_ua(user_agent)
9
- ua.os = parse_os(user_agent)
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 all_patterns
16
- @all_patterns ||= YAML.load_file(UserAgentParser.patterns_path)
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
- def patterns type
20
- @patterns ||= {}
21
- @patterns[type] ||= begin
22
- all_patterns[type].each do |p|
23
- p["regex"] = Regexp.new(p["regex"])
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 user_agent
29
- pattern, match = first_pattern_match(patterns("user_agent_parsers"), user_agent)
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 user_agent
38
- pattern, match = first_pattern_match(patterns("os_parsers"), user_agent)
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 first_pattern_match patterns, value
47
- for p in patterns
48
- if m = p["regex"].match(value)
49
- return [p, m]
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 pattern, match
56
- family, v1, v2, v3 = match[1], match[2], match[3], match[4]
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
- family = pattern["family_replacement"].sub('$1', family || '')
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
- v1 = pattern["v1_replacement"].sub('$1', v1 || '') if pattern["v1_replacement"]
61
- v2 = pattern["v2_replacement"].sub('$1', v2 || '') if pattern["v2_replacement"]
62
- v3 = pattern["v3_replacement"].sub('$1', v3 || '') if pattern["v3_replacement"]
63
- ua = UserAgent.new(family)
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 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
- os = pattern["os_replacement"].sub('$1', os || '') if pattern["os_replacement"]
71
- v1 = pattern["v1_replacement"].sub('$1', v1 || '') if pattern["v1_replacement"]
72
- v2 = pattern["v2_replacement"].sub('$1', v2 || '') if pattern["v2_replacement"]
73
- v3 = pattern["v3_replacement"].sub('$1', v3 || '') if pattern["v3_replacement"]
74
- v4 = pattern["v3_replacement"].sub('$1', v3 || '') if pattern["v4_replacement"]
75
- os = OperatingSystem.new(os)
76
- os.version = version_from_segments(v1, v2, v3, v4)
77
- os
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
- attr_accessor :family, :version, :os
5
+ # For backwards compatibility with older versions of this gem.
6
+ alias_method :family, :name
6
7
 
7
- def initialize(family="Other", version=nil, os=nil)
8
- self.family = family
9
- self.version = version
10
- self.os = os
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
- s = family
15
- s += " #{version}" if version
16
- s
16
+ string = name
17
+ string += " #{version}" if version
18
+ string
17
19
  end
18
20
 
19
21
  def inspect
20
- s = to_s
21
- s += " (#{os})" if os
22
- "#<#{self.class} #{s}>"
22
+ string = to_s
23
+ string += " (#{os})" if os
24
+ string += " (#{device})" if device
25
+ "#<#{self.class} #{string}>"
23
26
  end
24
-
25
- def ==(other)
26
- family == other.family &&
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
- attr_accessor :version
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
- self.version = version.to_s.strip
12
+ @version = version.to_s.strip
10
13
  end
11
14
 
12
- def segments
13
- version.scan(/\d+\-\d+|\d+[a-zA-Z]+$|\d+|[A-Za-z][0-9A-Za-z-]*$/).map do |s|
14
- /^\d+$/ =~ s ? s.to_i : s
15
- end
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 [](segment)
19
- segments[segment]
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 ==(other)
32
- version == other.version
34
+
35
+ def eql?(other)
36
+ self.class.eql?(other.class) &&
37
+ version == other.version
33
38
  end
34
39
 
35
- end
40
+ alias_method :==, :eql?
36
41
 
37
- end
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: '(webOSBrowser)/(\d+)\.(\d+)'
70
- - regex: '(webOS)/(\d+)\.(\d+)'
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: '(UC Browser)(\d+)\.(\d+)\.(\d+)'
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 Browser
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|Bunjaloo|Google Earth|Raven for Mac)/(\d+)\.(\d+)\.(\d+)'
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|BREW) (\d+)\.(\d+)\.?(\d+)?'
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: '(PLAYSTATION) (\d+)'
225
- family_replacement: 'PlayStation'
226
- - regex: '(PlayStation Portable)[^\d]+(\d+).(\d+)'
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: 'NokiaBrowser'
312
+ family_replacement: 'Nokia Browser'
270
313
  - regex: '(Series60)/5\.0'
271
- family_replacement: 'NokiaBrowser'
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: 'Nokia Series 40 Ovi Browser'
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: 'Blackberry WebKit'
327
+ family_replacement: 'BlackBerry WebKit'
283
328
  - regex: '(Black[bB]erry).+Version/(\d+)\.(\d+)\.(\d+)'
284
- family_replacement: 'Blackberry WebKit'
329
+ family_replacement: 'BlackBerry WebKit'
285
330
  - regex: '(Black[bB]erry)\s?(\d+)'
286
- family_replacement: 'Blackberry'
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: '(Nintendo 3DS).* Version/(\d+)\.(\d+)(?:\.(\w+))'
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
- - regex: '(Windows Phone 6\.5)'
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 OS'
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 OS) (\d+)\.(\d+)'
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: 'Blackberry OS'
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: '(webOS|hpwOS)/(\d+)\.(\d+)(?:\.(\d+))?'
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]+\; [A-Za-z]{2}\-[A-Za-z]{2}\; WOWMobile (.+) Build'
574
- - regex: 'Android[\- ][\d]+\.[\d]+\.[\d]+; [A-Za-z]{2}\-[A-Za-z]{2}\; (.+) Build'
575
- - regex: 'Android[\- ][\d]+\.[\d]+\-update1\; [A-Za-z]{2}\-[A-Za-z]{2}\; (.+) Build'
576
- - regex: 'Android[\- ][\d]+\.[\d]+\; [A-Za-z]{2}\-[A-Za-z]{2}\; (.+) Build'
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
- # Blackberry
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: 'Blackberry Playbook'
602
- - regex: '(Black[Bb]erry [0-9]+);'
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: '(Touchpad)/(\d+)\.(\d+)'
615
- device_replacement: 'HP Touchpad'
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]+)\_W\;FOMA'
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 Vodafone
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: 'Lenovo\_([A-Za-z0-9]+)'
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
- # Sony
941
+ # WebTV
803
942
  ##########
804
- - regex: '(PlayStation3 PPC)'
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\-|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)'
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|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)'
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\-|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: 1.0.2
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: 2012-11-10 00:00:00.000000000 Z
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.9.2
42
+ version: 1.8.7
42
43
  required_rubygems_version: !ruby/object:Gem::Requirement
43
44
  none: false
44
45
  requirements: