device_detector 1.0.4 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +8 -7
  4. data/lib/device_detector/browser.rb +364 -0
  5. data/lib/device_detector/client.rb +8 -0
  6. data/lib/device_detector/device.rb +1204 -2
  7. data/lib/device_detector/os.rb +39 -12
  8. data/lib/device_detector/parser.rb +1 -1
  9. data/lib/device_detector/version.rb +1 -1
  10. data/lib/device_detector/version_extractor.rb +28 -0
  11. data/lib/device_detector.rb +57 -13
  12. data/regexes/bots.yml +651 -61
  13. data/regexes/client/browser_engine.yml +7 -1
  14. data/regexes/client/browsers.yml +774 -78
  15. data/regexes/client/feed_readers.yml +4 -10
  16. data/regexes/client/libraries.yml +71 -2
  17. data/regexes/client/mediaplayers.yml +25 -1
  18. data/regexes/client/mobile_apps.yml +923 -73
  19. data/regexes/client/pim.yml +65 -2
  20. data/regexes/device/cameras.yml +5 -5
  21. data/regexes/device/car_browsers.yml +16 -0
  22. data/regexes/device/consoles.yml +13 -1
  23. data/regexes/device/mobiles.yml +17029 -3889
  24. data/regexes/device/notebooks.yml +114 -0
  25. data/regexes/device/portable_media_player.yml +36 -9
  26. data/regexes/device/shell_tv.yml +117 -0
  27. data/regexes/device/televisions.yml +439 -34
  28. data/regexes/oss.yml +620 -284
  29. metadata +9 -131
  30. data/.gitignore +0 -14
  31. data/.rubocop.yml +0 -49
  32. data/.ruby-version +0 -1
  33. data/.travis.yml +0 -14
  34. data/Gemfile +0 -8
  35. data/Rakefile +0 -85
  36. data/device_detector.gemspec +0 -27
  37. data/spec/device_detector/bot_fixtures_spec.rb +0 -30
  38. data/spec/device_detector/client_fixtures_spec.rb +0 -31
  39. data/spec/device_detector/concrete_user_agent_spec.rb +0 -135
  40. data/spec/device_detector/detector_fixtures_spec.rb +0 -100
  41. data/spec/device_detector/device_fixtures_spec.rb +0 -36
  42. data/spec/device_detector/device_spec.rb +0 -131
  43. data/spec/device_detector/memory_cache_spec.rb +0 -148
  44. data/spec/device_detector/model_extractor_spec.rb +0 -63
  45. data/spec/device_detector/os_fixtures_spec.rb +0 -26
  46. data/spec/device_detector/version_extractor_spec.rb +0 -79
  47. data/spec/device_detector_spec.rb +0 -189
  48. data/spec/fixtures/client/browser.yml +0 -2836
  49. data/spec/fixtures/client/feed_reader.yml +0 -199
  50. data/spec/fixtures/client/library.yml +0 -193
  51. data/spec/fixtures/client/mediaplayer.yml +0 -163
  52. data/spec/fixtures/client/mobile_app.yml +0 -217
  53. data/spec/fixtures/client/pim.yml +0 -115
  54. data/spec/fixtures/detector/bots.yml +0 -3726
  55. data/spec/fixtures/detector/camera.yml +0 -141
  56. data/spec/fixtures/detector/car_browser.yml +0 -81
  57. data/spec/fixtures/detector/console.yml +0 -321
  58. data/spec/fixtures/detector/desktop.yml +0 -5461
  59. data/spec/fixtures/detector/feature_phone.yml +0 -891
  60. data/spec/fixtures/detector/feed_reader.yml +0 -551
  61. data/spec/fixtures/detector/mediaplayer.yml +0 -253
  62. data/spec/fixtures/detector/mobile_apps.yml +0 -494
  63. data/spec/fixtures/detector/phablet.yml +0 -4167
  64. data/spec/fixtures/detector/portable_media_player.yml +0 -178
  65. data/spec/fixtures/detector/smart_display.yml +0 -61
  66. data/spec/fixtures/detector/smart_speaker.yml +0 -55
  67. data/spec/fixtures/detector/smartphone-1.yml +0 -9927
  68. data/spec/fixtures/detector/smartphone-10.yml +0 -9977
  69. data/spec/fixtures/detector/smartphone-11.yml +0 -9891
  70. data/spec/fixtures/detector/smartphone-12.yml +0 -9906
  71. data/spec/fixtures/detector/smartphone-13.yml +0 -9920
  72. data/spec/fixtures/detector/smartphone-14.yml +0 -2662
  73. data/spec/fixtures/detector/smartphone-2.yml +0 -9992
  74. data/spec/fixtures/detector/smartphone-3.yml +0 -9945
  75. data/spec/fixtures/detector/smartphone-4.yml +0 -9923
  76. data/spec/fixtures/detector/smartphone-5.yml +0 -9914
  77. data/spec/fixtures/detector/smartphone-6.yml +0 -9962
  78. data/spec/fixtures/detector/smartphone-7.yml +0 -9899
  79. data/spec/fixtures/detector/smartphone-8.yml +0 -9931
  80. data/spec/fixtures/detector/smartphone-9.yml +0 -9899
  81. data/spec/fixtures/detector/smartphone.yml +0 -9984
  82. data/spec/fixtures/detector/tablet-1.yml +0 -9995
  83. data/spec/fixtures/detector/tablet-2.yml +0 -9977
  84. data/spec/fixtures/detector/tablet-3.yml +0 -9959
  85. data/spec/fixtures/detector/tablet-4.yml +0 -4528
  86. data/spec/fixtures/detector/tablet.yml +0 -9971
  87. data/spec/fixtures/detector/tv.yml +0 -4933
  88. data/spec/fixtures/detector/unknown.yml +0 -3236
  89. data/spec/fixtures/detector/wearable.yml +0 -61
  90. data/spec/fixtures/device/camera.yml +0 -19
  91. data/spec/fixtures/device/car_browser.yml +0 -13
  92. data/spec/fixtures/device/console.yml +0 -79
  93. data/spec/fixtures/parser/oss.yml +0 -1082
  94. data/spec/fixtures/parser/vendorfragments.yml +0 -168
  95. data/spec/spec_helper.rb +0 -9
@@ -30,7 +30,7 @@ class DeviceDetector
30
30
  def os_info
31
31
  from_cache(['os_info', self.class.name, user_agent]) do
32
32
  os_name = NameExtractor.new(user_agent, regex_meta).call
33
- if os_name && short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase]
33
+ if os_name && (short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase])
34
34
  os_name = OPERATING_SYSTEMS[short]
35
35
  else
36
36
  short = 'UNK'
@@ -50,7 +50,7 @@ class DeviceDetector
50
50
  'AIX' => 'AIX',
51
51
  'AND' => 'Android',
52
52
  'AMG' => 'AmigaOS',
53
- 'ATV' => 'Apple TV',
53
+ 'ATV' => 'tvOS',
54
54
  'ARL' => 'Arch Linux',
55
55
  'BTR' => 'BackTrack',
56
56
  'SBA' => 'Bada',
@@ -58,29 +58,42 @@ class DeviceDetector
58
58
  'BLB' => 'BlackBerry OS',
59
59
  'QNX' => 'BlackBerry Tablet OS',
60
60
  'BMP' => 'Brew',
61
+ 'CAI' => 'Caixa Mágica',
61
62
  'CES' => 'CentOS',
62
63
  'COS' => 'Chrome OS',
63
64
  'CYN' => 'CyanogenMod',
64
65
  'DEB' => 'Debian',
66
+ 'DEE' => 'Deepin',
65
67
  'DFB' => 'DragonFly',
68
+ 'DVK' => 'DVKBuntu',
66
69
  'FED' => 'Fedora',
70
+ 'FEN' => 'Fenix',
67
71
  'FOS' => 'Firefox OS',
68
72
  'FIR' => 'Fire OS',
73
+ 'FRE' => 'Freebox',
69
74
  'BSD' => 'FreeBSD',
75
+ 'FYD' => 'FydeOS',
70
76
  'GNT' => 'Gentoo',
77
+ 'GRI' => 'GridOS',
71
78
  'GTV' => 'Google TV',
72
79
  'HPX' => 'HP-UX',
73
80
  'HAI' => 'Haiku OS',
81
+ 'IPA' => 'iPadOS',
82
+ 'HAR' => 'HarmonyOS',
83
+ 'HAS' => 'HasCodingOS',
74
84
  'IRI' => 'IRIX',
75
85
  'INF' => 'Inferno',
86
+ 'JME' => 'Java ME',
76
87
  'KOS' => 'KaiOS',
77
88
  'KNO' => 'Knoppix',
78
89
  'KBT' => 'Kubuntu',
79
90
  'LIN' => 'GNU/Linux',
80
91
  'LBT' => 'Lubuntu',
92
+ 'LOS' => 'Lumin OS',
81
93
  'VLN' => 'VectorLinux',
82
94
  'MAC' => 'Mac',
83
95
  'MAE' => 'Maemo',
96
+ 'MAG' => 'Mageia',
84
97
  'MDR' => 'Mandriva',
85
98
  'SMG' => 'MeeGo',
86
99
  'MCD' => 'MocorDroid',
@@ -89,21 +102,28 @@ class DeviceDetector
89
102
  'MOR' => 'MorphOS',
90
103
  'NBS' => 'NetBSD',
91
104
  'MTK' => 'MTK / Nucleus',
105
+ 'MRE' => 'MRE',
92
106
  'WII' => 'Nintendo',
93
107
  'NDS' => 'Nintendo Mobile',
94
108
  'OS2' => 'OS/2',
95
109
  'T64' => 'OSF1',
96
110
  'OBS' => 'OpenBSD',
111
+ 'OWR' => 'OpenWrt',
97
112
  'ORD' => 'Ordissimo',
113
+ 'PCL' => 'PCLinuxOS',
98
114
  'PSP' => 'PlayStation Portable',
99
115
  'PS3' => 'PlayStation',
100
116
  'RHT' => 'Red Hat',
101
117
  'ROS' => 'RISC OS',
118
+ 'ROK' => 'Roku OS',
119
+ 'RSO' => 'Rosa',
102
120
  'REM' => 'Remix OS',
121
+ 'REX' => 'REX',
103
122
  'RZD' => 'RazoDroiD',
104
123
  'SAB' => 'Sabayon',
105
124
  'SSE' => 'SUSE',
106
125
  'SAF' => 'Sailfish OS',
126
+ 'SEE' => 'SeewoOS',
107
127
  'SLW' => 'Slackware',
108
128
  'SOS' => 'Solaris',
109
129
  'SYL' => 'Syllable',
@@ -116,7 +136,9 @@ class DeviceDetector
116
136
  'TIZ' => 'Tizen',
117
137
  'TOS' => 'TmaxOS',
118
138
  'UBT' => 'Ubuntu',
139
+ 'WAS' => 'watchOS',
119
140
  'WTV' => 'WebTV',
141
+ 'WHS' => 'Whale OS',
120
142
  'WIN' => 'Windows',
121
143
  'WCE' => 'Windows CE',
122
144
  'WIO' => 'Windows IoT',
@@ -125,7 +147,7 @@ class DeviceDetector
125
147
  'WRT' => 'Windows RT',
126
148
  'XBX' => 'Xbox',
127
149
  'XBT' => 'Xubuntu',
128
- 'YNS' => 'YunOs',
150
+ 'YNS' => 'YunOS',
129
151
  'IOS' => 'iOS',
130
152
  'POS' => 'palmOS',
131
153
  'WOS' => 'webOS'
@@ -133,37 +155,42 @@ class DeviceDetector
133
155
 
134
156
  DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}) do |(short, long), h|
135
157
  h[long.downcase] = short
136
- end
158
+ end.freeze
137
159
 
138
160
  OS_FAMILIES = {
139
- 'Android' => %w[AND CYN FIR REM RZD MLD MCD YNS],
161
+ 'Android' => %w[AND CYN FIR REM RZD MLD MCD YNS GRI HAR],
140
162
  'AmigaOS' => %w[AMG MOR],
141
- 'Apple TV' => ['ATV'],
142
163
  'BlackBerry' => %w[BLB QNX],
143
164
  'Brew' => ['BMP'],
144
165
  'BeOS' => %w[BEO HAI],
145
- 'Chrome OS' => ['COS'],
166
+ 'Chrome OS' => %w[COS FYD SEE],
146
167
  'Firefox OS' => %w[FOS KOS],
147
168
  'Gaming Console' => %w[WII PS3],
148
169
  'Google TV' => ['GTV'],
149
170
  'IBM' => ['OS2'],
150
- 'iOS' => ['IOS'],
171
+ 'iOS' => %w[IOS ATV WAS IPA],
151
172
  'RISC OS' => ['ROS'],
152
- 'GNU/Linux' => %w[LIN ARL DEB KNO MIN UBT KBT XBT LBT FED RHT VLN MDR GNT SAB SLW SSE CES BTR SAF ORD TOS],
173
+ 'GNU/Linux' => %w[
174
+ LIN ARL DEB KNO MIN UBT KBT XBT LBT FED
175
+ RHT VLN MDR GNT SAB SLW SSE CES BTR SAF
176
+ ORD TOS RSO DEE FRE MAG FEN CAI PCL HAS
177
+ LOS DVK ROK OWR
178
+ ],
153
179
  'Mac' => ['MAC'],
154
180
  'Mobile Gaming Console' => %w[PSP NDS XBX],
155
- 'Real-time OS' => %w[MTK TDX],
181
+ 'Real-time OS' => %w[MTK TDX MRE JME REX],
156
182
  'Other Mobile' => %w[WOS POS SBA TIZ SMG MAE],
157
183
  'Symbian' => %w[SYM SYS SY3 S60 S40],
158
184
  'Unix' => %w[SOS AIX HPX BSD NBS OBS DFB SYL IRI T64 INF],
159
185
  'WebTV' => ['WTV'],
160
186
  'Windows' => ['WIN'],
161
- 'Windows Mobile' => %w[WPH WMO WCE WRT WIO]
187
+ 'Windows Mobile' => %w[WPH WMO WCE WRT WIO],
188
+ 'Other Smart TV' => ['WHS']
162
189
  }.freeze
163
190
 
164
191
  FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family, oss), h|
165
192
  oss.each { |os| h[os] = family }
166
- end
193
+ end.freeze
167
194
 
168
195
  def filenames
169
196
  ['oss.yml']
@@ -85,7 +85,7 @@ class DeviceDetector
85
85
  end
86
86
 
87
87
  def build_regex(src)
88
- Regexp.new('(?:^|[^A-Z0-9\-_]|[^A-Z0-9\-]_|sprd-)(?:' + src + ')', Regexp::IGNORECASE)
88
+ Regexp.new('(?:^|[^A-Z0-9\-_]|[^A-Z0-9\-]_|sprd-|MZ-)(?:' + src + ')', Regexp::IGNORECASE)
89
89
  end
90
90
 
91
91
  def from_cache(key)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class DeviceDetector
4
- VERSION = '1.0.4'
4
+ VERSION = '1.0.7'
5
5
  end
@@ -2,8 +2,36 @@
2
2
 
3
3
  class DeviceDetector
4
4
  class VersionExtractor < MetadataExtractor
5
+ MAJOR_VERSION_2 = Gem::Version.new('2.0')
6
+ MAJOR_VERSION_3 = Gem::Version.new('3.0')
7
+ MAJOR_VERSION_4 = Gem::Version.new('4.0')
8
+ MAJOR_VERSION_8 = Gem::Version.new('8.0')
9
+
10
+ def call
11
+ simple_version = super&.chomp('.')
12
+
13
+ return simple_version unless simple_version&.empty?
14
+
15
+ os_version_by_regexes
16
+ end
17
+
5
18
  private
6
19
 
20
+ def os_version_by_regexes
21
+ version_matches = regex_meta[:versions]
22
+ return '' unless version_matches
23
+
24
+ version_matches.detect do |matcher|
25
+ user_agent.match(matcher[:regex]) do |match_data|
26
+ return matcher[:version].gsub(/\$(\d)/) do
27
+ match_data[Regexp.last_match(1).to_i].to_s
28
+ end.strip
29
+ end
30
+ end
31
+
32
+ ''
33
+ end
34
+
7
35
  def metadata_string
8
36
  String(regex_meta[:version])
9
37
  end
@@ -13,6 +13,7 @@ require 'device_detector/bot'
13
13
  require 'device_detector/client'
14
14
  require 'device_detector/device'
15
15
  require 'device_detector/os'
16
+ require 'device_detector/browser'
16
17
 
17
18
  class DeviceDetector
18
19
  attr_reader :user_agent
@@ -46,7 +47,10 @@ class DeviceDetector
46
47
  end
47
48
 
48
49
  def device_brand
49
- device.brand
50
+ # Assume all devices running iOS / Mac OS are from Apple
51
+ brand = device.brand
52
+ brand = 'Apple' if brand.nil? && ['Apple TV', 'iOS', 'Mac'].include?(os_name)
53
+ brand
50
54
  end
51
55
 
52
56
  def device_type
@@ -59,15 +63,19 @@ class DeviceDetector
59
63
  # that won't have a detected browser, but can still be detected. So we check the useragent for
60
64
  # Chrome instead.
61
65
  if t.nil? && os.family == 'Android' && user_agent =~ build_regex('Chrome\/[\.0-9]*')
62
- if user_agent =~ build_regex('Chrome\/[\.0-9]* Mobile')
66
+ if user_agent =~ build_regex('(?:Mobile|eliboM) Safari\/')
63
67
  t = 'smartphone'
64
- elsif user_agent =~ build_regex('Chrome\/[\.0-9]* (?!Mobile)')
68
+ elsif user_agent =~ build_regex('(?!Mobile )Safari\/')
65
69
  t = 'tablet'
66
70
  end
67
71
  end
68
72
 
73
+ # Some UA contain the fragment 'Android; Tablet;' or 'Opera Tablet', so we assume those devices
74
+ # as tablets
69
75
  t = 'tablet' if t.nil? && android_tablet_fragment? || opera_tablet?
70
76
 
77
+ # Some user agents simply contain the fragment 'Android; Mobile;', so we assume those devices
78
+ # as smartphones
71
79
  t = 'smartphone' if t.nil? && android_mobile_fragment?
72
80
 
73
81
  # Android up to 3.0 was designed for smartphones only. But as 3.0,
@@ -78,10 +86,12 @@ class DeviceDetector
78
86
  # So were are expecting that all devices running Android < 2 are
79
87
  # smartphones Devices running Android 3.X are tablets. Device type
80
88
  # of Android 2.X and 4.X+ are unknown
81
- if t.nil? && os.short_name == 'AND' && os.full_version && !os.full_version.empty?
82
- if os.full_version < '2'
89
+ if t.nil? && os_name == 'Android' && os.full_version && !os.full_version.empty?
90
+ full_version = Gem::Version.new(os.full_version)
91
+ if full_version < VersionExtractor::MAJOR_VERSION_2
83
92
  t = 'smartphone'
84
- elsif os.full_version >= '3' && os.full_version < '4'
93
+ elsif full_version >= VersionExtractor::MAJOR_VERSION_3 && \
94
+ full_version < VersionExtractor::MAJOR_VERSION_4
85
95
  t = 'tablet'
86
96
  end
87
97
  end
@@ -89,6 +99,9 @@ class DeviceDetector
89
99
  # All detected feature phones running android are more likely a smartphone
90
100
  t = 'smartphone' if t == 'feature phone' && os.family == 'Android'
91
101
 
102
+ # All unknown devices under running Java ME are more likely a features phones
103
+ t = 'feature phone' if t.nil? && os_name == 'Java ME'
104
+
92
105
  # According to http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
93
106
  # Internet Explorer 10 introduces the "Touch" UA string token. If this token is present at the
94
107
  # end of the UA string, the computer has touch capability, and is running Windows 8 (or later).
@@ -97,19 +110,29 @@ class DeviceDetector
97
110
  # As most touch enabled devices are tablets and only a smaller part are desktops/notebooks we
98
111
  # assume that all Windows 8 touch devices are tablets.
99
112
  if t.nil? && touch_enabled? &&
100
- (os.short_name == 'WRT' || (os.short_name == 'WIN' && os.full_version && os.full_version >= '8'))
113
+ (os_name == 'Windows RT' ||
114
+ (os_name == 'Windows' && os.full_version &&
115
+ Gem::Version.new(os.full_version) >= VersionExtractor::MAJOR_VERSION_8))
101
116
  t = 'tablet'
102
117
  end
103
118
 
119
+ # All devices running Opera TV Store are assumed to be a tv
104
120
  t = 'tv' if opera_tv_store?
105
121
 
122
+ # All devices running Tizen TV or SmartTV are assumed to be a tv
123
+ t = 'tv' if t.nil? && tizen_samsung_tv?
124
+
125
+ # Devices running Kylo or Espital TV Browsers are assumed to be a TV
106
126
  t = 'tv' if t.nil? && ['Kylo', 'Espial TV Browser'].include?(client.name)
107
127
 
108
- # set device type to desktop for all devices running a desktop os that were
109
- # not detected as an other device type
110
- t = 'desktop' if t.nil? && os.desktop? && !puffin_browser?
128
+ has_desktop = t != 'desktop' && desktop_string? && desktop_fragment?
129
+ t = 'desktop' if has_desktop
111
130
 
112
- t
131
+ # set device type to desktop for all devices running a desktop os that were not detected as
132
+ # another device type
133
+ return t if t || !desktop?
134
+
135
+ 'desktop'
113
136
  end
114
137
 
115
138
  def known?
@@ -175,6 +198,10 @@ class DeviceDetector
175
198
  user_agent =~ build_regex('Android(?: \d.\d(?:.\d)?)?; Mobile;')
176
199
  end
177
200
 
201
+ def desktop_fragment?
202
+ user_agent =~ build_regex('Desktop (x(?:32|64)|WOW64);')
203
+ end
204
+
178
205
  def touch_enabled?
179
206
  user_agent =~ build_regex('Touch')
180
207
  end
@@ -187,9 +214,26 @@ class DeviceDetector
187
214
  user_agent =~ build_regex('Opera Tablet')
188
215
  end
189
216
 
217
+ def tizen_samsung_tv?
218
+ user_agent =~ build_regex('SmartTV|Tizen.+ TV .+$')
219
+ end
220
+
221
+ def uses_mobile_browser?
222
+ client.browser? && client.mobile_only_browser?
223
+ end
224
+
190
225
  # This is a workaround until we support detecting mobile only browsers
191
- def puffin_browser?
192
- client.name == 'Puffin'
226
+ def desktop_string?
227
+ user_agent =~ /Desktop/
228
+ end
229
+
230
+ def desktop?
231
+ return false if os_name.nil? || os_name == '' || os_name == 'UNK'
232
+
233
+ # Check for browsers available for mobile devices only
234
+ return false if uses_mobile_browser?
235
+
236
+ os.desktop?
193
237
  end
194
238
 
195
239
  def build_regex(src)