device_detector 1.0.3 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +15 -0
- data/README.md +8 -7
- data/lib/device_detector/bot.rb +2 -2
- data/lib/device_detector/browser.rb +364 -0
- data/lib/device_detector/client.rb +11 -2
- data/lib/device_detector/device.rb +1247 -22
- data/lib/device_detector/memory_cache.rb +5 -5
- data/lib/device_detector/metadata_extractor.rb +7 -8
- data/lib/device_detector/model_extractor.rb +3 -3
- data/lib/device_detector/name_extractor.rb +2 -2
- data/lib/device_detector/os.rb +150 -116
- data/lib/device_detector/parser.rb +23 -10
- data/lib/device_detector/version.rb +1 -1
- data/lib/device_detector/version_extractor.rb +29 -2
- data/lib/device_detector.rb +73 -40
- data/regexes/bots.yml +868 -62
- data/regexes/client/browser_engine.yml +11 -2
- data/regexes/client/browsers.yml +1132 -112
- data/regexes/client/feed_readers.yml +5 -11
- data/regexes/client/libraries.yml +86 -2
- data/regexes/client/mediaplayers.yml +39 -3
- data/regexes/client/mobile_apps.yml +940 -66
- data/regexes/client/pim.yml +66 -3
- data/regexes/device/cameras.yml +6 -6
- data/regexes/device/car_browsers.yml +23 -3
- data/regexes/device/consoles.yml +15 -3
- data/regexes/device/mobiles.yml +18351 -3566
- data/regexes/device/notebooks.yml +114 -0
- data/regexes/device/portable_media_player.yml +36 -9
- data/regexes/device/shell_tv.yml +117 -0
- data/regexes/device/televisions.yml +440 -35
- data/regexes/oss.yml +635 -284
- data/regexes/vendorfragments.yml +5 -1
- metadata +21 -118
- data/.gitignore +0 -14
- data/.travis.yml +0 -14
- data/Gemfile +0 -8
- data/Rakefile +0 -96
- data/device_detector.gemspec +0 -26
- data/spec/device_detector/bot_fixtures_spec.rb +0 -30
- data/spec/device_detector/client_fixtures_spec.rb +0 -31
- data/spec/device_detector/concrete_user_agent_spec.rb +0 -135
- data/spec/device_detector/detector_fixtures_spec.rb +0 -100
- data/spec/device_detector/device_fixtures_spec.rb +0 -36
- data/spec/device_detector/device_spec.rb +0 -151
- data/spec/device_detector/memory_cache_spec.rb +0 -148
- data/spec/device_detector/model_extractor_spec.rb +0 -63
- data/spec/device_detector/os_fixtures_spec.rb +0 -26
- data/spec/device_detector/version_extractor_spec.rb +0 -79
- data/spec/device_detector_spec.rb +0 -189
- data/spec/fixtures/client/browser.yml +0 -2206
- data/spec/fixtures/client/feed_reader.yml +0 -199
- data/spec/fixtures/client/library.yml +0 -175
- data/spec/fixtures/client/mediaplayer.yml +0 -163
- data/spec/fixtures/client/mobile_app.yml +0 -193
- data/spec/fixtures/client/pim.yml +0 -115
- data/spec/fixtures/detector/bots.yml +0 -3260
- data/spec/fixtures/detector/camera.yml +0 -121
- data/spec/fixtures/detector/car_browser.yml +0 -21
- data/spec/fixtures/detector/console.yml +0 -281
- data/spec/fixtures/detector/desktop.yml +0 -5361
- data/spec/fixtures/detector/feature_phone.yml +0 -891
- data/spec/fixtures/detector/feed_reader.yml +0 -551
- data/spec/fixtures/detector/mediaplayer.yml +0 -210
- data/spec/fixtures/detector/mobile_apps.yml +0 -456
- data/spec/fixtures/detector/phablet.yml +0 -3785
- data/spec/fixtures/detector/portable_media_player.yml +0 -178
- data/spec/fixtures/detector/smart_display.yml +0 -61
- data/spec/fixtures/detector/smartphone-1.yml +0 -9953
- data/spec/fixtures/detector/smartphone-10.yml +0 -9924
- data/spec/fixtures/detector/smartphone-11.yml +0 -9889
- data/spec/fixtures/detector/smartphone-12.yml +0 -8655
- data/spec/fixtures/detector/smartphone-2.yml +0 -9967
- data/spec/fixtures/detector/smartphone-3.yml +0 -9887
- data/spec/fixtures/detector/smartphone-4.yml +0 -9911
- data/spec/fixtures/detector/smartphone-5.yml +0 -9933
- data/spec/fixtures/detector/smartphone-6.yml +0 -9923
- data/spec/fixtures/detector/smartphone-7.yml +0 -9892
- data/spec/fixtures/detector/smartphone-8.yml +0 -9896
- data/spec/fixtures/detector/smartphone-9.yml +0 -9928
- data/spec/fixtures/detector/smartphone.yml +0 -9984
- data/spec/fixtures/detector/tablet-1.yml +0 -10023
- data/spec/fixtures/detector/tablet-2.yml +0 -9968
- data/spec/fixtures/detector/tablet-3.yml +0 -7787
- data/spec/fixtures/detector/tablet.yml +0 -9951
- data/spec/fixtures/detector/tv.yml +0 -3333
- data/spec/fixtures/detector/unknown.yml +0 -3283
- data/spec/fixtures/device/camera.yml +0 -19
- data/spec/fixtures/device/car_browser.yml +0 -7
- data/spec/fixtures/device/console.yml +0 -79
- data/spec/fixtures/parser/oss.yml +0 -1047
- data/spec/fixtures/parser/vendorfragments.yml +0 -162
- data/spec/spec_helper.rb +0 -9
@@ -51,12 +51,12 @@ class DeviceDetector
|
|
51
51
|
def purge_cache
|
52
52
|
key_size = data.size
|
53
53
|
|
54
|
-
if key_size
|
55
|
-
# always remove about 1/3 of keys to reduce garbage collecting
|
56
|
-
amount_of_keys = key_size / 3
|
54
|
+
return if key_size < max_keys
|
57
55
|
|
58
|
-
|
59
|
-
|
56
|
+
# always remove about 1/3 of keys to reduce garbage collecting
|
57
|
+
amount_of_keys = key_size / 3
|
58
|
+
|
59
|
+
data.keys.first(amount_of_keys).each { |key| data.delete(key) }
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class DeviceDetector
|
2
4
|
class MetadataExtractor < Struct.new(:user_agent, :regex_meta)
|
3
|
-
|
4
5
|
def call
|
5
6
|
regex_meta.any? ? extract_metadata : nil
|
6
7
|
end
|
@@ -8,22 +9,20 @@ class DeviceDetector
|
|
8
9
|
private
|
9
10
|
|
10
11
|
def metadata_string
|
11
|
-
message = "#{
|
12
|
-
|
12
|
+
message = "#{name} (a child of MetadataExtractor) must implement the '#{__method__}' method."
|
13
|
+
raise NotImplementedError, message
|
13
14
|
end
|
14
15
|
|
15
16
|
def extract_metadata
|
16
17
|
user_agent.match(regex) do |match_data|
|
17
|
-
metadata_string.gsub(/\$(\d)/)
|
18
|
-
match_data[
|
19
|
-
|
18
|
+
metadata_string.gsub(/\$(\d)/) do
|
19
|
+
match_data[Regexp.last_match(1).to_i].to_s
|
20
|
+
end.strip
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
24
|
def regex
|
24
25
|
@regex ||= regex_meta[:regex]
|
25
26
|
end
|
26
|
-
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class DeviceDetector
|
2
4
|
class ModelExtractor < MetadataExtractor
|
3
|
-
|
4
5
|
def call
|
5
|
-
s = super.to_s.gsub('_',' ').strip
|
6
|
+
s = super.to_s.gsub('_', ' ').strip
|
6
7
|
s = s.gsub(/ TD$/i, '')
|
7
8
|
|
8
9
|
return nil if s == 'Build'
|
@@ -19,6 +20,5 @@ class DeviceDetector
|
|
19
20
|
def regex
|
20
21
|
@regex ||= regex_meta[:regex_model] || regex_meta[:regex]
|
21
22
|
end
|
22
|
-
|
23
23
|
end
|
24
24
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class DeviceDetector
|
2
4
|
class NameExtractor < MetadataExtractor
|
3
|
-
|
4
5
|
def call
|
5
6
|
if /\$[0-9]/ =~ metadata_string
|
6
7
|
extract_metadata
|
@@ -14,6 +15,5 @@ class DeviceDetector
|
|
14
15
|
def metadata_string
|
15
16
|
regex_meta[:name]
|
16
17
|
end
|
17
|
-
|
18
18
|
end
|
19
19
|
end
|
data/lib/device_detector/os.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'set'
|
2
4
|
|
3
5
|
class DeviceDetector
|
4
6
|
class OS < Parser
|
5
|
-
|
6
7
|
def name
|
7
8
|
os_info[:name]
|
8
9
|
end
|
@@ -29,7 +30,7 @@ class DeviceDetector
|
|
29
30
|
def os_info
|
30
31
|
from_cache(['os_info', self.class.name, user_agent]) do
|
31
32
|
os_name = NameExtractor.new(user_agent, regex_meta).call
|
32
|
-
if os_name && short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase]
|
33
|
+
if os_name && (short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase])
|
33
34
|
os_name = OPERATING_SYSTEMS[short]
|
34
35
|
else
|
35
36
|
short = 'UNK'
|
@@ -38,128 +39,161 @@ class DeviceDetector
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
41
|
-
DESKTOP_OSS = Set.new(
|
42
|
+
DESKTOP_OSS = Set.new(
|
43
|
+
[
|
44
|
+
'AmigaOS', 'IBM', 'GNU/Linux', 'Mac', 'Unix', 'Windows', 'BeOS', 'Chrome OS'
|
45
|
+
]
|
46
|
+
)
|
42
47
|
|
43
48
|
# OS short codes mapped to long names
|
44
49
|
OPERATING_SYSTEMS = {
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
50
|
+
'AIX' => 'AIX',
|
51
|
+
'AND' => 'Android',
|
52
|
+
'AMG' => 'AmigaOS',
|
53
|
+
'ATV' => 'tvOS',
|
54
|
+
'ARL' => 'Arch Linux',
|
55
|
+
'BTR' => 'BackTrack',
|
56
|
+
'SBA' => 'Bada',
|
57
|
+
'BEO' => 'BeOS',
|
58
|
+
'BLB' => 'BlackBerry OS',
|
59
|
+
'QNX' => 'BlackBerry Tablet OS',
|
60
|
+
'BMP' => 'Brew',
|
61
|
+
'CAI' => 'Caixa Mágica',
|
62
|
+
'CES' => 'CentOS',
|
63
|
+
'COS' => 'Chrome OS',
|
64
|
+
'CYN' => 'CyanogenMod',
|
65
|
+
'DEB' => 'Debian',
|
66
|
+
'DEE' => 'Deepin',
|
67
|
+
'DFB' => 'DragonFly',
|
68
|
+
'DVK' => 'DVKBuntu',
|
69
|
+
'FED' => 'Fedora',
|
70
|
+
'FEN' => 'Fenix',
|
71
|
+
'FOS' => 'Firefox OS',
|
72
|
+
'FIR' => 'Fire OS',
|
73
|
+
'FRE' => 'Freebox',
|
74
|
+
'BSD' => 'FreeBSD',
|
75
|
+
'FYD' => 'FydeOS',
|
76
|
+
'GNT' => 'Gentoo',
|
77
|
+
'GRI' => 'GridOS',
|
78
|
+
'GTV' => 'Google TV',
|
79
|
+
'HPX' => 'HP-UX',
|
80
|
+
'HAI' => 'Haiku OS',
|
81
|
+
'IPA' => 'iPadOS',
|
82
|
+
'HAR' => 'HarmonyOS',
|
83
|
+
'HAS' => 'HasCodingOS',
|
84
|
+
'IRI' => 'IRIX',
|
85
|
+
'INF' => 'Inferno',
|
86
|
+
'JME' => 'Java ME',
|
87
|
+
'KOS' => 'KaiOS',
|
88
|
+
'KNO' => 'Knoppix',
|
89
|
+
'KBT' => 'Kubuntu',
|
90
|
+
'LIN' => 'GNU/Linux',
|
91
|
+
'LBT' => 'Lubuntu',
|
92
|
+
'LOS' => 'Lumin OS',
|
93
|
+
'VLN' => 'VectorLinux',
|
94
|
+
'MAC' => 'Mac',
|
95
|
+
'MAE' => 'Maemo',
|
96
|
+
'MAG' => 'Mageia',
|
97
|
+
'MDR' => 'Mandriva',
|
98
|
+
'SMG' => 'MeeGo',
|
99
|
+
'MCD' => 'MocorDroid',
|
100
|
+
'MIN' => 'Mint',
|
101
|
+
'MLD' => 'MildWild',
|
102
|
+
'MOR' => 'MorphOS',
|
103
|
+
'NBS' => 'NetBSD',
|
104
|
+
'MTK' => 'MTK / Nucleus',
|
105
|
+
'MRE' => 'MRE',
|
106
|
+
'WII' => 'Nintendo',
|
107
|
+
'NDS' => 'Nintendo Mobile',
|
108
|
+
'OS2' => 'OS/2',
|
109
|
+
'T64' => 'OSF1',
|
110
|
+
'OBS' => 'OpenBSD',
|
111
|
+
'OWR' => 'OpenWrt',
|
112
|
+
'ORD' => 'Ordissimo',
|
113
|
+
'PCL' => 'PCLinuxOS',
|
114
|
+
'PSP' => 'PlayStation Portable',
|
115
|
+
'PS3' => 'PlayStation',
|
116
|
+
'RHT' => 'Red Hat',
|
117
|
+
'ROS' => 'RISC OS',
|
118
|
+
'ROK' => 'Roku OS',
|
119
|
+
'RSO' => 'Rosa',
|
120
|
+
'REM' => 'Remix OS',
|
121
|
+
'REX' => 'REX',
|
122
|
+
'RZD' => 'RazoDroiD',
|
123
|
+
'SAB' => 'Sabayon',
|
124
|
+
'SSE' => 'SUSE',
|
125
|
+
'SAF' => 'Sailfish OS',
|
126
|
+
'SEE' => 'SeewoOS',
|
127
|
+
'SLW' => 'Slackware',
|
128
|
+
'SOS' => 'Solaris',
|
129
|
+
'SYL' => 'Syllable',
|
130
|
+
'SYM' => 'Symbian',
|
131
|
+
'SYS' => 'Symbian OS',
|
132
|
+
'S40' => 'Symbian OS Series 40',
|
133
|
+
'S60' => 'Symbian OS Series 60',
|
134
|
+
'SY3' => 'Symbian^3',
|
135
|
+
'TDX' => 'ThreadX',
|
136
|
+
'TIZ' => 'Tizen',
|
137
|
+
'TOS' => 'TmaxOS',
|
138
|
+
'UBT' => 'Ubuntu',
|
139
|
+
'WAS' => 'watchOS',
|
140
|
+
'WTV' => 'WebTV',
|
141
|
+
'WHS' => 'Whale OS',
|
142
|
+
'WIN' => 'Windows',
|
143
|
+
'WCE' => 'Windows CE',
|
144
|
+
'WIO' => 'Windows IoT',
|
145
|
+
'WMO' => 'Windows Mobile',
|
146
|
+
'WPH' => 'Windows Phone',
|
147
|
+
'WRT' => 'Windows RT',
|
148
|
+
'XBX' => 'Xbox',
|
149
|
+
'XBT' => 'Xubuntu',
|
150
|
+
'YNS' => 'YunOS',
|
151
|
+
'IOS' => 'iOS',
|
152
|
+
'POS' => 'palmOS',
|
153
|
+
'WOS' => 'webOS'
|
154
|
+
}.freeze
|
155
|
+
|
156
|
+
DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}) do |(short, long), h|
|
157
|
+
h[long.downcase] = short
|
158
|
+
end.freeze
|
128
159
|
|
129
160
|
OS_FAMILIES = {
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
161
|
+
'Android' => %w[AND CYN FIR REM RZD MLD MCD YNS GRI HAR],
|
162
|
+
'AmigaOS' => %w[AMG MOR],
|
163
|
+
'BlackBerry' => %w[BLB QNX],
|
164
|
+
'Brew' => ['BMP'],
|
165
|
+
'BeOS' => %w[BEO HAI],
|
166
|
+
'Chrome OS' => %w[COS FYD SEE],
|
167
|
+
'Firefox OS' => %w[FOS KOS],
|
168
|
+
'Gaming Console' => %w[WII PS3],
|
169
|
+
'Google TV' => ['GTV'],
|
170
|
+
'IBM' => ['OS2'],
|
171
|
+
'iOS' => %w[IOS ATV WAS IPA],
|
172
|
+
'RISC OS' => ['ROS'],
|
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
|
+
],
|
179
|
+
'Mac' => ['MAC'],
|
180
|
+
'Mobile Gaming Console' => %w[PSP NDS XBX],
|
181
|
+
'Real-time OS' => %w[MTK TDX MRE JME REX],
|
182
|
+
'Other Mobile' => %w[WOS POS SBA TIZ SMG MAE],
|
183
|
+
'Symbian' => %w[SYM SYS SY3 S60 S40],
|
184
|
+
'Unix' => %w[SOS AIX HPX BSD NBS OBS DFB SYL IRI T64 INF],
|
185
|
+
'WebTV' => ['WTV'],
|
186
|
+
'Windows' => ['WIN'],
|
187
|
+
'Windows Mobile' => %w[WPH WMO WCE WRT WIO],
|
188
|
+
'Other Smart TV' => ['WHS']
|
189
|
+
}.freeze
|
190
|
+
|
191
|
+
FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family, oss), h|
|
192
|
+
oss.each { |os| h[os] = family }
|
193
|
+
end.freeze
|
158
194
|
|
159
195
|
def filenames
|
160
196
|
['oss.yml']
|
161
197
|
end
|
162
|
-
|
163
198
|
end
|
164
|
-
|
165
199
|
end
|
@@ -1,7 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class DeviceDetector
|
2
|
-
class Parser
|
4
|
+
class Parser
|
5
|
+
ROOT = File.expand_path('../..', __dir__)
|
6
|
+
|
7
|
+
REGEX_CACHE = ::DeviceDetector::MemoryCache.new({})
|
8
|
+
private_constant :REGEX_CACHE
|
9
|
+
|
10
|
+
def initialize(user_agent)
|
11
|
+
@user_agent = user_agent
|
12
|
+
end
|
3
13
|
|
4
|
-
|
14
|
+
attr_reader :user_agent
|
5
15
|
|
6
16
|
def name
|
7
17
|
from_cache(['name', self.class.name, user_agent]) do
|
@@ -32,17 +42,17 @@ class DeviceDetector
|
|
32
42
|
end
|
33
43
|
|
34
44
|
def filenames
|
35
|
-
|
45
|
+
raise NotImplementedError
|
36
46
|
end
|
37
47
|
|
38
48
|
def filepaths
|
39
49
|
filenames.map do |filename|
|
40
|
-
[
|
50
|
+
[filename.to_sym, File.join(ROOT, 'regexes', filename)]
|
41
51
|
end
|
42
52
|
end
|
43
53
|
|
44
54
|
def regexes_for(file_paths)
|
45
|
-
|
55
|
+
REGEX_CACHE.get_or_set(file_paths) do
|
46
56
|
load_regexes(file_paths).flat_map { |path, regex| parse_regexes(path, regex) }
|
47
57
|
end
|
48
58
|
end
|
@@ -54,16 +64,20 @@ class DeviceDetector
|
|
54
64
|
def symbolize_keys!(object)
|
55
65
|
case object
|
56
66
|
when Array
|
57
|
-
object.map!{ |v| symbolize_keys!(v) }
|
67
|
+
object.map! { |v| symbolize_keys!(v) }
|
58
68
|
when Hash
|
59
|
-
|
69
|
+
keys = object.keys
|
70
|
+
keys.each do |k|
|
71
|
+
object[k.to_sym] = symbolize_keys!(object.delete(k)) if k.is_a?(String)
|
72
|
+
end
|
60
73
|
end
|
61
74
|
object
|
62
75
|
end
|
63
76
|
|
64
77
|
def parse_regexes(path, raw_regexes)
|
65
78
|
raw_regexes.map do |meta|
|
66
|
-
|
79
|
+
raise "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String
|
80
|
+
|
67
81
|
meta[:regex] = build_regex(meta[:regex])
|
68
82
|
meta[:path] = path
|
69
83
|
meta
|
@@ -71,12 +85,11 @@ class DeviceDetector
|
|
71
85
|
end
|
72
86
|
|
73
87
|
def build_regex(src)
|
74
|
-
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)
|
75
89
|
end
|
76
90
|
|
77
91
|
def from_cache(key)
|
78
92
|
DeviceDetector.cache.get_or_set(key) { yield }
|
79
93
|
end
|
80
|
-
|
81
94
|
end
|
82
95
|
end
|
@@ -1,12 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class DeviceDetector
|
2
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
|
3
17
|
|
4
18
|
private
|
5
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
|
+
|
6
35
|
def metadata_string
|
7
36
|
String(regex_meta[:version])
|
8
37
|
end
|
9
|
-
|
10
38
|
end
|
11
39
|
end
|
12
|
-
|