user_agent_parser 2.4.0 → 2.4.1
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.
Potentially problematic release.
This version of user_agent_parser might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/user_agent_parser +1 -0
- data/lib/user_agent_parser.rb +4 -2
- data/lib/user_agent_parser/cli.rb +12 -16
- data/lib/user_agent_parser/device.rb +5 -3
- data/lib/user_agent_parser/operating_system.rb +5 -3
- data/lib/user_agent_parser/parser.rb +28 -26
- data/lib/user_agent_parser/user_agent.rb +5 -3
- data/lib/user_agent_parser/version.rb +6 -4
- data/vendor/uap-core/regexes.yaml +78 -2
- metadata +2 -3
- data/Readme.md +0 -143
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11927dac3bd4e88a9a7be095093a664fd96b8111
|
4
|
+
data.tar.gz: 21b998a0a2f0016ad4e75b6e8678e855369dadee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e374cd5e96daca43ef27002052edb5e1101d35c77a1f18dda370b1c28702709a86a9a2b36d830162b9a068a5259ac2d3d2a1532ae2efaf294d4a955224bcfd6
|
7
|
+
data.tar.gz: 020cef494b4307e0921978e213c7c243cbb70c075f17a6f238e95a40dfd999d38c896abae12d17cf1afd834fea9f3be533d308f08e607127b07be1b82a1ed5b5
|
data/bin/user_agent_parser
CHANGED
data/lib/user_agent_parser.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'user_agent_parser/parser'
|
2
4
|
require 'user_agent_parser/user_agent'
|
3
5
|
require 'user_agent_parser/version'
|
@@ -5,10 +7,10 @@ require 'user_agent_parser/operating_system'
|
|
5
7
|
require 'user_agent_parser/device'
|
6
8
|
|
7
9
|
module UserAgentParser
|
8
|
-
DefaultPatternsPath = File.join(File.dirname(__FILE__),
|
10
|
+
DefaultPatternsPath = File.join(File.dirname(__FILE__), '../vendor/uap-core/regexes.yaml')
|
9
11
|
|
10
12
|
# Parse the given +user_agent_string+, returning a +UserAgent+
|
11
|
-
def self.parse(user_agent_string, options={})
|
13
|
+
def self.parse(user_agent_string, options = {})
|
12
14
|
Parser.new(options).parse(user_agent_string)
|
13
15
|
end
|
14
16
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module UserAgentParser
|
2
4
|
class Cli
|
3
5
|
def initialize(user_agent, options = {})
|
@@ -11,9 +13,7 @@ module UserAgentParser
|
|
11
13
|
elsif @options[:name]
|
12
14
|
@user_agent.name
|
13
15
|
elsif @options[:version]
|
14
|
-
with_version
|
15
|
-
version.to_s
|
16
|
-
end
|
16
|
+
with_version(&:to_s)
|
17
17
|
elsif @options[:major]
|
18
18
|
major
|
19
19
|
elsif @options[:minor]
|
@@ -21,13 +21,13 @@ module UserAgentParser
|
|
21
21
|
elsif @options[:os]
|
22
22
|
@user_agent.os.to_s
|
23
23
|
elsif format = @options[:format]
|
24
|
-
format
|
25
|
-
gsub('%f', @user_agent.family)
|
26
|
-
gsub('%n', @user_agent.name)
|
27
|
-
gsub('%v', version.to_s)
|
28
|
-
gsub('%M', major.to_s)
|
29
|
-
gsub('%m', minor.to_s)
|
30
|
-
gsub('%o', @user_agent.os.to_s)
|
24
|
+
format
|
25
|
+
.gsub('%f', @user_agent.family)
|
26
|
+
.gsub('%n', @user_agent.name)
|
27
|
+
.gsub('%v', version.to_s)
|
28
|
+
.gsub('%M', major.to_s)
|
29
|
+
.gsub('%m', minor.to_s)
|
30
|
+
.gsub('%o', @user_agent.os.to_s)
|
31
31
|
else
|
32
32
|
@user_agent.to_s
|
33
33
|
end
|
@@ -36,15 +36,11 @@ module UserAgentParser
|
|
36
36
|
private
|
37
37
|
|
38
38
|
def major
|
39
|
-
with_version
|
40
|
-
version.major
|
41
|
-
end
|
39
|
+
with_version(&:major)
|
42
40
|
end
|
43
41
|
|
44
42
|
def minor
|
45
|
-
with_version
|
46
|
-
version.minor
|
47
|
-
end
|
43
|
+
with_version(&:minor)
|
48
44
|
end
|
49
45
|
|
50
46
|
def version
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module UserAgentParser
|
2
4
|
class Device
|
3
5
|
attr_reader :family, :model, :brand
|
4
6
|
|
5
|
-
|
7
|
+
alias name family
|
6
8
|
|
7
9
|
def initialize(family = nil, model = nil, brand = nil)
|
8
10
|
@family = family || 'Other'
|
@@ -15,13 +17,13 @@ module UserAgentParser
|
|
15
17
|
end
|
16
18
|
|
17
19
|
def inspect
|
18
|
-
"#<#{self.class} #{
|
20
|
+
"#<#{self.class} #{self}>"
|
19
21
|
end
|
20
22
|
|
21
23
|
def eql?(other)
|
22
24
|
self.class.eql?(other.class) && family == other.family
|
23
25
|
end
|
24
26
|
|
25
|
-
|
27
|
+
alias == eql?
|
26
28
|
end
|
27
29
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module UserAgentParser
|
2
4
|
class OperatingSystem
|
3
5
|
attr_reader :family, :version
|
4
6
|
|
5
|
-
|
7
|
+
alias name family
|
6
8
|
|
7
9
|
def initialize(family = 'Other', version = nil)
|
8
10
|
@family = family
|
@@ -18,7 +20,7 @@ module UserAgentParser
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def inspect
|
21
|
-
"#<#{self.class} #{
|
23
|
+
"#<#{self.class} #{self}>"
|
22
24
|
end
|
23
25
|
|
24
26
|
def eql?(other)
|
@@ -27,6 +29,6 @@ module UserAgentParser
|
|
27
29
|
version == other.version
|
28
30
|
end
|
29
31
|
|
30
|
-
|
32
|
+
alias == eql?
|
31
33
|
end
|
32
34
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
|
3
5
|
module UserAgentParser
|
@@ -5,7 +7,7 @@ module UserAgentParser
|
|
5
7
|
class Parser
|
6
8
|
attr_reader :patterns_path
|
7
9
|
|
8
|
-
def initialize(options={})
|
10
|
+
def initialize(options = {})
|
9
11
|
@patterns_path = options[:patterns_path] || UserAgentParser::DefaultPatternsPath
|
10
12
|
@ua_patterns, @os_patterns, @device_patterns = load_patterns(patterns_path)
|
11
13
|
end
|
@@ -24,11 +26,11 @@ module UserAgentParser
|
|
24
26
|
# Parse all the regexs
|
25
27
|
yml.each_pair do |type, patterns|
|
26
28
|
patterns.each do |pattern|
|
27
|
-
pattern[
|
29
|
+
pattern['regex'] = Regexp.new(pattern['regex'], pattern['regex_flag'] == 'i')
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
|
-
[
|
33
|
+
[yml['user_agent_parsers'], yml['os_parsers'], yml['device_parsers']]
|
32
34
|
end
|
33
35
|
|
34
36
|
def parse_ua(user_agent, os = nil, device = nil)
|
@@ -63,7 +65,7 @@ module UserAgentParser
|
|
63
65
|
|
64
66
|
def first_pattern_match(patterns, value)
|
65
67
|
patterns.each do |pattern|
|
66
|
-
if match = pattern[
|
68
|
+
if match = pattern['regex'].match(value)
|
67
69
|
return [pattern, match]
|
68
70
|
end
|
69
71
|
end
|
@@ -73,24 +75,24 @@ module UserAgentParser
|
|
73
75
|
def user_agent_from_pattern_match(pattern, match, os = nil, device = nil)
|
74
76
|
family, v1, v2, v3, v4 = match[1], match[2], match[3], match[4], match[5]
|
75
77
|
|
76
|
-
if pattern[
|
77
|
-
family = pattern[
|
78
|
+
if pattern['family_replacement']
|
79
|
+
family = pattern['family_replacement'].sub('$1', family || '')
|
78
80
|
end
|
79
81
|
|
80
|
-
if pattern[
|
81
|
-
v1 = pattern[
|
82
|
+
if pattern['v1_replacement']
|
83
|
+
v1 = pattern['v1_replacement'].sub('$2', v1 || '')
|
82
84
|
end
|
83
85
|
|
84
|
-
if pattern[
|
85
|
-
v2 = pattern[
|
86
|
+
if pattern['v2_replacement']
|
87
|
+
v2 = pattern['v2_replacement'].sub('$3', v2 || '')
|
86
88
|
end
|
87
89
|
|
88
|
-
if pattern[
|
89
|
-
v3 = pattern[
|
90
|
+
if pattern['v3_replacement']
|
91
|
+
v3 = pattern['v3_replacement'].sub('$4', v3 || '')
|
90
92
|
end
|
91
93
|
|
92
|
-
if pattern[
|
93
|
-
v4 = pattern[
|
94
|
+
if pattern['v4_replacement']
|
95
|
+
v4 = pattern['v4_replacement'].sub('$5', v4 || '')
|
94
96
|
end
|
95
97
|
|
96
98
|
version = version_from_segments(v1, v2, v3, v4)
|
@@ -101,24 +103,24 @@ module UserAgentParser
|
|
101
103
|
def os_from_pattern_match(pattern, match)
|
102
104
|
os, v1, v2, v3, v4 = match[1], match[2], match[3], match[4], match[5]
|
103
105
|
|
104
|
-
if pattern[
|
105
|
-
os = pattern[
|
106
|
+
if pattern['os_replacement']
|
107
|
+
os = pattern['os_replacement'].sub('$1', os || '')
|
106
108
|
end
|
107
109
|
|
108
|
-
if pattern[
|
109
|
-
v1 = pattern[
|
110
|
+
if pattern['os_v1_replacement']
|
111
|
+
v1 = pattern['os_v1_replacement'].sub('$2', v1 || '')
|
110
112
|
end
|
111
113
|
|
112
|
-
if pattern[
|
113
|
-
v2 = pattern[
|
114
|
+
if pattern['os_v2_replacement']
|
115
|
+
v2 = pattern['os_v2_replacement'].sub('$3', v2 || '')
|
114
116
|
end
|
115
117
|
|
116
|
-
if pattern[
|
117
|
-
v3 = pattern[
|
118
|
+
if pattern['os_v3_replacement']
|
119
|
+
v3 = pattern['os_v3_replacement'].sub('$4', v3 || '')
|
118
120
|
end
|
119
121
|
|
120
|
-
if pattern[
|
121
|
-
v4 = pattern[
|
122
|
+
if pattern['os_v4_replacement']
|
123
|
+
v4 = pattern['os_v4_replacement'].sub('$5', v4 || '')
|
122
124
|
end
|
123
125
|
|
124
126
|
version = version_from_segments(v1, v2, v3, v4)
|
@@ -131,8 +133,8 @@ module UserAgentParser
|
|
131
133
|
family = model = match[1]
|
132
134
|
brand = nil
|
133
135
|
|
134
|
-
if pattern[
|
135
|
-
family = pattern[
|
136
|
+
if pattern['device_replacement']
|
137
|
+
family = pattern['device_replacement']
|
136
138
|
match.each_with_index { |m,i| family = family.sub("$#{i}", m) }
|
137
139
|
end
|
138
140
|
if pattern["model_replacement"]
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module UserAgentParser
|
2
4
|
class UserAgent
|
3
5
|
attr_reader :family, :version, :os, :device
|
4
6
|
|
5
|
-
|
7
|
+
alias name family
|
6
8
|
|
7
9
|
def initialize(family = nil, version = nil, os = nil, device = nil)
|
8
10
|
@family = family || 'Other'
|
@@ -26,11 +28,11 @@ module UserAgentParser
|
|
26
28
|
|
27
29
|
def eql?(other)
|
28
30
|
self.class.eql?(other.class) &&
|
29
|
-
|
31
|
+
family == other.family &&
|
30
32
|
version == other.version &&
|
31
33
|
os == other.os
|
32
34
|
end
|
33
35
|
|
34
|
-
|
36
|
+
alias == eql?
|
35
37
|
end
|
36
38
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module UserAgentParser
|
2
4
|
class Version
|
3
5
|
|
@@ -6,14 +8,14 @@ module UserAgentParser
|
|
6
8
|
SEGMENTS_REGEX = /\d+\-\d+|\d+[a-zA-Z]+$|\d+|[A-Za-z][0-9A-Za-z-]*$/
|
7
9
|
|
8
10
|
attr_reader :version
|
9
|
-
alias
|
11
|
+
alias to_s version
|
10
12
|
|
11
13
|
def initialize(*args)
|
12
14
|
if args.length == 1 && args.first.is_a?(String)
|
13
15
|
@version = args.first.to_s.strip
|
14
16
|
else
|
15
17
|
@segments = args.map(&:to_s).map(&:strip)
|
16
|
-
@version = segments.join(
|
18
|
+
@version = segments.join('.')
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
@@ -34,7 +36,7 @@ module UserAgentParser
|
|
34
36
|
end
|
35
37
|
|
36
38
|
def inspect
|
37
|
-
"#<#{self.class} #{
|
39
|
+
"#<#{self.class} #{self}>"
|
38
40
|
end
|
39
41
|
|
40
42
|
def eql?(other)
|
@@ -42,7 +44,7 @@ module UserAgentParser
|
|
42
44
|
version == other.version
|
43
45
|
end
|
44
46
|
|
45
|
-
|
47
|
+
alias == eql?
|
46
48
|
|
47
49
|
# Private
|
48
50
|
def segments
|
@@ -1,6 +1,27 @@
|
|
1
1
|
user_agent_parsers:
|
2
2
|
#### SPECIAL CASES TOP ####
|
3
3
|
|
4
|
+
# CFNetwork Podcast catcher Applications
|
5
|
+
- regex: '(ESPN)[%20| ]+Radio/(\d+)\.(\d+)\.(\d+) CFNetwork'
|
6
|
+
- regex: '(Antenna)/(\d+) CFNetwork'
|
7
|
+
family_replacement: 'AntennaPod'
|
8
|
+
- regex: '(TopPodcasts)Pro/(\d+) CFNetwork'
|
9
|
+
- regex: '(MusicDownloader)Lite/(\d+)\.(\d+)\.(\d+) CFNetwork'
|
10
|
+
- regex: '^(.*)-iPad/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
|
11
|
+
- regex: '^(.*)-iPhone/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
|
12
|
+
- regex: '^(.*)/(\d+)\.?(\d+)?.?(\d+)?.?(\d+)? CFNetwork'
|
13
|
+
|
14
|
+
# Podcast catchers
|
15
|
+
- regex: '(espn\.go)'
|
16
|
+
family_replacement: 'ESPN'
|
17
|
+
- regex: '(espnradio\.com)'
|
18
|
+
family_replacement: 'ESPN'
|
19
|
+
- regex: 'ESPN APP$'
|
20
|
+
family_replacement: 'ESPN'
|
21
|
+
- regex: '(audioboom\.com)'
|
22
|
+
family_replacement: 'AudioBoom'
|
23
|
+
- regex: ' (Rivo) RHYTHM'
|
24
|
+
|
4
25
|
# @note: iOS / OSX Applications
|
5
26
|
- regex: '(CFNetwork)(?:/(\d+)\.(\d+)\.?(\d+)?)?'
|
6
27
|
family_replacement: 'CFNetwork'
|
@@ -48,6 +69,10 @@ user_agent_parsers:
|
|
48
69
|
# Downloader ...
|
49
70
|
- regex: '(Google-HTTP-Java-Client|Apache-HttpClient|http%20client|Python-urllib|HttpMonitor|TLSProber|WinHTTP|JNLP|okhttp)(?:[ /](\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
50
71
|
|
72
|
+
# Pinterestbot
|
73
|
+
- regex: '(Pinterest(?:bot)?)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?[;\s\(]+\+https://www.pinterest.com/bot.html'
|
74
|
+
family_replacement: 'Pinterestbot'
|
75
|
+
|
51
76
|
# Bots
|
52
77
|
- regex: '(1470\.net crawler|50\.nu|8bo Crawler Bot|Aboundex|Accoona-[A-z]+-Agent|AdsBot-Google(?:-[a-z]+)?|altavista|AppEngine-Google|archive.*?\.org_bot|archiver|Ask Jeeves|[Bb]ai[Dd]u[Ss]pider(?:-[A-Za-z]+)*|bingbot|BingPreview|blitzbot|BlogBridge|Bloglovin|BoardReader(?: [A-Za-z]+)*|boitho.com-dc|BotSeer|\b\w*favicon\w*\b|\bYeti(?:-[a-z]+)?|Catchpoint(?: bot)?|[Cc]harlotte|Checklinks|clumboot|Comodo HTTP\(S\) Crawler|Comodo-Webinspector-Crawler|ConveraCrawler|CRAWL-E|CrawlConvera|Daumoa(?:-feedfetcher)?|Feed Seeker Bot|Feedbin|findlinks|Flamingo_SearchEngine|FollowSite Bot|furlbot|Genieo|gigabot|GomezAgent|gonzo1|(?:[a-zA-Z]+-)?Googlebot(?:-[a-zA-Z]+)?|Google SketchUp|grub-client|gsa-crawler|heritrix|HiddenMarket|holmes|HooWWWer|htdig|ia_archiver|ICC-Crawler|Icarus6j|ichiro(?:/mobile)?|IconSurf|IlTrovatore(?:-Setaccio)?|InfuzApp|Innovazion Crawler|InternetArchive|IP2[a-z]+Bot|jbot\b|KaloogaBot|Kraken|Kurzor|larbin|LEIA|LesnikBot|Linguee Bot|LinkAider|LinkedInBot|Lite Bot|Llaut|lycos|Mail\.RU_Bot|masscan|masidani_bot|Mediapartners-Google|Microsoft .*? Bot|mogimogi|mozDex|MJ12bot|msnbot(?:-media *)?|msrbot|Mtps Feed Aggregation System|netresearch|Netvibes|NewsGator[^/]*|^NING|Nutch[^/]*|Nymesis|ObjectsSearch|Orbiter|OOZBOT|PagePeeker|PagesInventory|PaxleFramework|Peeplo Screenshot Bot|PlantyNet_WebRobot|Pompos|Qwantify|Read%20Later|Reaper|RedCarpet|Retreiver|Riddler|Rival IQ|scooter|Scrapy|Scrubby|searchsight|seekbot|semanticdiscovery|Simpy|SimplePie|SEOstats|SimpleRSS|SiteCon|Slackbot-LinkExpanding|Slack-ImgProxy|Slurp|snappy|Speedy Spider|Squrl Java|Stringer|TheUsefulbot|ThumbShotsBot|Thumbshots\.ru|Tiny Tiny RSS|TwitterBot|WhatsApp|URL2PNG|Vagabondo|VoilaBot|^vortex|Votay bot|^voyager|WASALive.Bot|Web-sniffer|WebThumb|WeSEE:[A-z]+|WhatWeb|WIRE|WordPress|Wotbox|www\.almaden\.ibm\.com|Xenu(?:.s)? Link Sleuth|Xerka [A-z]+Bot|yacy(?:bot)?|Yahoo[a-z]*Seeker|Yahoo! Slurp|Yandex\w+|YodaoBot(?:-[A-z]+)?|YottaaMonitor|Yowedo|^Zao|^Zao-Crawler|ZeBot_www\.ze\.bz|ZooShot|ZyBorg)(?:[ /]v?(\d+)(?:\.(\d+)(?:\.(\d+))?)?)?'
|
53
78
|
|
@@ -68,11 +93,11 @@ user_agent_parsers:
|
|
68
93
|
|
69
94
|
# Social Networks
|
70
95
|
# Facebook
|
71
|
-
- regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)(?:\.(\d
|
96
|
+
- regex: '\[FB.*;(FBAV)/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
|
72
97
|
family_replacement: 'Facebook'
|
73
98
|
# Pinterest
|
74
99
|
- regex: '\[(Pinterest)/[^\]]+\]'
|
75
|
-
- regex: '(Pinterest)(?: for Android(?: Tablet)?)?/(\d+)(?:\.(\d+)(?:\.(\d
|
100
|
+
- regex: '(Pinterest)(?: for Android(?: Tablet)?)?/(\d+)(?:\.(\d+)(?:\.(\d+))?)?'
|
76
101
|
|
77
102
|
# Pale Moon
|
78
103
|
- regex: '(PaleMoon)/(\d+)\.(\d+)\.?(\d+)?'
|
@@ -307,6 +332,9 @@ user_agent_parsers:
|
|
307
332
|
# AOL Browser (IE-based)
|
308
333
|
- regex: '(AOL) (\d+)\.(\d+); AOLBuild (\d+)'
|
309
334
|
|
335
|
+
# Podcast catcher Applications using iTunes
|
336
|
+
- regex: '(PodCruncher|Downcast)[ /]?(\d+)\.?(\d+)?\.?(\d+)?\.?(\d+)?'
|
337
|
+
|
310
338
|
#### END SPECIAL CASES TOP ####
|
311
339
|
|
312
340
|
#### MAIN CASES - this catches > 50% of all browsers ####
|
@@ -412,6 +440,54 @@ user_agent_parsers:
|
|
412
440
|
# Baca Berita App News Reader
|
413
441
|
- regex: '(BacaBerita App)\/(\d+)\.(\d+)\.(\d+)'
|
414
442
|
|
443
|
+
# Podcast catchers
|
444
|
+
- regex: '^(bPod|Pocket Casts|Player FM)$'
|
445
|
+
- regex: '^(AlexaMediaPlayer|VLC)/(\d+)\.(\d+)\.([^.\s]+)'
|
446
|
+
- regex: '^(AntennaPod|WMPlayer|Zune|Podkicker|Radio|ExoPlayerDemo|Overcast|PocketTunes|NSPlayer|okhttp|DoggCatcher|QuickNews|QuickTime|Peapod|Podcasts|GoldenPod|VLC|Spotify|Miro|MediaGo|Juice|iPodder|gPodder|Banshee)/(\d+)\.(\d+)\.?(\d+)?\.?(\d+)?'
|
447
|
+
- regex: '^(Peapod|Liferea)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
|
448
|
+
- regex: '^(bPod|Player FM) BMID/(\S+)'
|
449
|
+
- regex: '^(Podcast ?Addict)/v(\d+) '
|
450
|
+
- regex: '^(Podcast ?Addict) '
|
451
|
+
family_replacement: 'PodcastAddict'
|
452
|
+
- regex: '(Replay) AV'
|
453
|
+
- regex: '(VOX) Music Player'
|
454
|
+
- regex: '(CITA) RSS Aggregator/(\d+)\.(\d+)'
|
455
|
+
- regex: '(Pocket Casts)$'
|
456
|
+
- regex: '(Player FM)$'
|
457
|
+
- regex: '(LG Player|Doppler|FancyMusic|MediaMonkey|Clementine) (\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
|
458
|
+
- regex: '(philpodder)/(\d+)\.(\d+)\.?([^.\s]+)?\.?([^.\s]+)?'
|
459
|
+
- regex: '(Player FM|Pocket Casts|DoggCatcher|Spotify|MediaMonkey|MediaGo|BashPodder)'
|
460
|
+
- regex: '(QuickTime)\.(\d+)\.(\d+)\.(\d+)'
|
461
|
+
- regex: '(Kinoma)(\d+)'
|
462
|
+
- regex: '(Fancy) Cloud Music (\d+)\.(\d+)'
|
463
|
+
family_replacement: 'FancyMusic'
|
464
|
+
- regex: 'EspnDownloadManager'
|
465
|
+
family_replacement: 'ESPN'
|
466
|
+
- regex: '(ESPN) Radio (\d+)\.(\d+)\.?(\d+)? ?[rv:]?(\d+)? '
|
467
|
+
- regex: '(podracer|jPodder) v ?(\d+)\.(\d+)\.?(\d+)?'
|
468
|
+
- regex: '(ZDM)/(\d+)\.(\d+)[; ]?'
|
469
|
+
- regex: '(Zune|BeyondPod) (\d+)\.?(\d+)?[\);]'
|
470
|
+
- regex: '(WMPlayer)/(\d+)\.(\d+)\.(\d+)\.(\d+)'
|
471
|
+
- regex: '^(Lavf)'
|
472
|
+
family_replacement: 'WMPlayer'
|
473
|
+
- regex: '^(RSSRadio)[ /]?(\d+)?'
|
474
|
+
- regex: '(RSS_Radio) (\d+)\.(\d+)'
|
475
|
+
family_replacement: 'RSSRadio'
|
476
|
+
- regex: '(Podkicker) \S+/(\d+)\.(\d+)\.(\d+)'
|
477
|
+
family_replacement: 'Podkicker'
|
478
|
+
- regex: '^(HTC) Streaming Player \S+ / \S+ / \S+ / (\d+)\.(\d+)\.?(\d+)?'
|
479
|
+
- regex: '^(Stitcher)/iOS'
|
480
|
+
- regex: '^(Stitcher)/Android'
|
481
|
+
- regex: '^(VLC) .*version (\d+)\.(\d+)\.(\d+)'
|
482
|
+
- regex: ' (VLC) for'
|
483
|
+
- regex: '(vlc)/(\d+)\.(\d+)\.(\d+)'
|
484
|
+
family_replacement: 'VLC'
|
485
|
+
- regex: '^(foobar)\S+/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
|
486
|
+
- regex: '^(Clementine)\S+ ([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
|
487
|
+
- regex: '(amarok)/([^.\s]+)\.([^.\s]+)?\.?([^.\s]+)?'
|
488
|
+
family_replacement: 'Amarok'
|
489
|
+
- regex: '(Custom)-Feed Reader'
|
490
|
+
|
415
491
|
# Browser major_version.minor_version.beta_version (space instead of slash)
|
416
492
|
- regex: '(iRider|Crazy Browser|SkipStone|iCab|Lunascape|Sleipnir|Maemo Browser) (\d+)\.(\d+)\.(\d+)'
|
417
493
|
# Browser major_version.minor_version (space instead of slash)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: user_agent_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.
|
4
|
+
version: 2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Lucas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coveralls
|
@@ -33,7 +33,6 @@ extensions: []
|
|
33
33
|
extra_rdoc_files: []
|
34
34
|
files:
|
35
35
|
- MIT-LICENSE
|
36
|
-
- Readme.md
|
37
36
|
- bin/user_agent_parser
|
38
37
|
- lib/user_agent_parser.rb
|
39
38
|
- lib/user_agent_parser/cli.rb
|
data/Readme.md
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
# UserAgentParser [](http://travis-ci.org/ua-parser/uap-ruby) [](https://coveralls.io/github/ua-parser/uap-ruby)
|
2
|
-
|
3
|
-
UserAgentParser is a simple, comprehensive Ruby gem for parsing user agent strings. It uses [BrowserScope](http://www.browserscope.org/)'s [parsing patterns](https://github.com/ua-parser/uap-core).
|
4
|
-
|
5
|
-
## Supported Rubies
|
6
|
-
|
7
|
-
* Ruby 2.4
|
8
|
-
* Ruby 2.3
|
9
|
-
* Ruby 2.2
|
10
|
-
* Ruby 2.1
|
11
|
-
* Ruby 2.0
|
12
|
-
* Ruby 1.9.3
|
13
|
-
* Ruby 1.9.2
|
14
|
-
* JRuby
|
15
|
-
|
16
|
-
## Installation
|
17
|
-
|
18
|
-
```bash
|
19
|
-
$ gem install user_agent_parser
|
20
|
-
```
|
21
|
-
|
22
|
-
## Example usage
|
23
|
-
|
24
|
-
```ruby
|
25
|
-
require 'user_agent_parser'
|
26
|
-
=> true
|
27
|
-
user_agent = UserAgentParser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
|
28
|
-
=> #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
|
29
|
-
user_agent.to_s
|
30
|
-
=> "IE 9.0"
|
31
|
-
user_agent.family
|
32
|
-
=> "IE"
|
33
|
-
user_agent.version.to_s
|
34
|
-
=> "9.0"
|
35
|
-
user_agent.version.major
|
36
|
-
=> "9"
|
37
|
-
user_agent.version.minor
|
38
|
-
=> "0"
|
39
|
-
operating_system = user_agent.os
|
40
|
-
=> #<UserAgentParser::OperatingSystem Windows Vista>
|
41
|
-
operating_system.to_s
|
42
|
-
=> "Windows Vista"
|
43
|
-
|
44
|
-
# Device information can also be determined from some devices
|
45
|
-
user_agent = UserAgentParser.parse "Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G930T Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.0 Chrome/51.0.2704.106 Mobile Safari/537.36"
|
46
|
-
=> #<UserAgentParser::UserAgent Samsung Internet 5.0 (Android 7.0) (Samsung SM-G930T)>
|
47
|
-
user_agent.device.family
|
48
|
-
=> "Samsung SM-G930T"
|
49
|
-
user_agent.device.brand
|
50
|
-
=> "Samsung"
|
51
|
-
user_agent.device.model
|
52
|
-
=> "SM-G930T"
|
53
|
-
|
54
|
-
user_agent = UserAgentParser.parse "Mozilla/5.0 (iPad; CPU OS 10_2_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) GSA/23.1.148956103 Mobile/14D27 Safari/600.1.4"
|
55
|
-
=> #<UserAgentParser::UserAgent Mobile Safari 10.2.1 (iOS 10.2.1) (iPad)>
|
56
|
-
irb(main):026:0> user_agent.device.family
|
57
|
-
=> "iPad"
|
58
|
-
irb(main):027:0> user_agent.device.brand
|
59
|
-
=> "Apple"
|
60
|
-
irb(main):028:0> user_agent.device.model
|
61
|
-
=> "iPad"
|
62
|
-
|
63
|
-
|
64
|
-
# The parser database will be loaded and parsed on every call to
|
65
|
-
# UserAgentParser.parse. To avoid this, instantiate your own Parser instance.
|
66
|
-
parser = UserAgentParser::Parser.new
|
67
|
-
parser.parse 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0;)'
|
68
|
-
=> #<UserAgentParser::UserAgent IE 9.0 (Windows Vista)>
|
69
|
-
parser.parse 'Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.5.24 Version/10.53'
|
70
|
-
=> #<UserAgentParser::UserAgent Opera 10.53 (Windows XP)>
|
71
|
-
```
|
72
|
-
|
73
|
-
In a larger application, you could store a parser in a global to avoid repeat pattern loading:
|
74
|
-
|
75
|
-
```ruby
|
76
|
-
module MyApplication
|
77
|
-
|
78
|
-
# Instantiate the parser on load as it's quite expensive
|
79
|
-
USER_AGENT_PARSER = UserAgentParser::Parser.new
|
80
|
-
|
81
|
-
def self.user_agent_parser
|
82
|
-
USER_AGENT_PARSER
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
```
|
87
|
-
|
88
|
-
## The pattern database
|
89
|
-
|
90
|
-
The [ua-parser database](https://github.com/ua-parser/uap-core/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!).
|
91
|
-
|
92
|
-
You can also specify the path to your own, updated and/or customised `regexes.yaml` file as a second argument to `UserAgentParser.parse`:
|
93
|
-
|
94
|
-
```ruby
|
95
|
-
UserAgentParser.parse(ua_string, patterns_path: '/some/path/to/regexes.yaml')
|
96
|
-
```
|
97
|
-
|
98
|
-
or when instantiating a `UserAgentParser::Parser`:
|
99
|
-
|
100
|
-
```ruby
|
101
|
-
UserAgentParser::Parser.new(patterns_path: '/some/path/to/regexes.yaml').parse(ua_string)
|
102
|
-
```
|
103
|
-
|
104
|
-
## Command line tool
|
105
|
-
|
106
|
-
The gem incldes a `user_agent_parser` bin command which will read from
|
107
|
-
standard input, parse each line and print the result, for example:
|
108
|
-
|
109
|
-
```bash
|
110
|
-
$ cat > SOME-FILE-WITH-USER-AGENTS.txt
|
111
|
-
USER_AGENT_1
|
112
|
-
USER_AGENT_2
|
113
|
-
...
|
114
|
-
$ cat SOME-FILE-WITH-USER-AGENTS.txt | user_agent_parser --format '%f %M' | distribution
|
115
|
-
```
|
116
|
-
|
117
|
-
See `user_agent_parser -h` for more information.
|
118
|
-
|
119
|
-
## Contributing
|
120
|
-
|
121
|
-
1. Fork
|
122
|
-
2. Hack
|
123
|
-
3. `rake test`
|
124
|
-
4. Send a pull request
|
125
|
-
|
126
|
-
All accepted pull requests will earn you commit and release rights.
|
127
|
-
|
128
|
-
## Releasing a new version
|
129
|
-
|
130
|
-
1. Update the version in `user_agent_parser.gemspec`
|
131
|
-
2. `git commit user_agent_parser.gemspec` with the following message format:
|
132
|
-
|
133
|
-
Version x.x.x
|
134
|
-
|
135
|
-
Changelog:
|
136
|
-
* Some new feature
|
137
|
-
* Some new bug fix
|
138
|
-
3. `rake release`
|
139
|
-
4. Create a [new Github release](https://github.com/ua-parser/uap-ruby/releases/new)
|
140
|
-
|
141
|
-
## License
|
142
|
-
|
143
|
-
MIT
|