woothee 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -0
- data/Makefile +13 -0
- data/Rakefile +13 -0
- data/lib/woothee/appliance.rb +46 -0
- data/lib/woothee/browser.rb +89 -0
- data/lib/woothee/crawler.rb +153 -0
- data/lib/woothee/dataset.rb +278 -0
- data/lib/woothee/misc.rb +67 -0
- data/lib/woothee/mobilephone.rb +94 -0
- data/lib/woothee/os.rb +166 -0
- data/lib/woothee/util.rb +24 -0
- data/lib/woothee.rb +159 -0
- data/spec/00_valid_spec.rb +13 -0
- data/spec/01_dataset_spec.rb +16 -0
- data/spec/02_run_testsets_spec.rb +39 -0
- data/woothee.gemspec +20 -0
- metadata +79 -0
data/Gemfile
ADDED
data/Makefile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
$:.unshift File.join(File.dirname(__FILE__), "lib")
|
6
|
+
|
7
|
+
require 'rspec/core'
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
|
10
|
+
task :default => :spec
|
11
|
+
|
12
|
+
desc "Run all specs in spec directory"
|
13
|
+
RSpec::Core::RakeTask.new(:spec)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'woothee/dataset'
|
4
|
+
require 'woothee/util'
|
5
|
+
|
6
|
+
module Woothee::Appliance
|
7
|
+
extend Woothee::Util
|
8
|
+
|
9
|
+
def self.challenge_playstation(ua, result)
|
10
|
+
data = case
|
11
|
+
when ua.index('PSP (PlayStation Portable);') then Woothee::DataSet.get('PSP')
|
12
|
+
when ua.index('PlayStation Vita') then Woothee::DataSet.get('PSVita')
|
13
|
+
when ua.index('PLAYSTATION 3;') then Woothee::DataSet.get('PS3')
|
14
|
+
else nil
|
15
|
+
end
|
16
|
+
return false unless data
|
17
|
+
|
18
|
+
update_map(result, data)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.challenge_nintendo(ua, result)
|
23
|
+
data = case
|
24
|
+
when ua.index('Nintendo 3DS;') then Woothee::DataSet.get('Nintendo3DS')
|
25
|
+
when ua.index('Nintendo DSi;') then Woothee::DataSet.get('NintendoDSi')
|
26
|
+
when ua.index('Nintendo Wii;') then Woothee::DataSet.get('NintendoWii')
|
27
|
+
else nil
|
28
|
+
end
|
29
|
+
return false unless data
|
30
|
+
|
31
|
+
update_map(result, data)
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.challenge_digitaltv(ua, result)
|
36
|
+
data = if ua.index('InettvBrowser/')
|
37
|
+
Woothee::DataSet.get('DigitalTV')
|
38
|
+
else
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
return false unless data
|
42
|
+
|
43
|
+
update_map(result, data)
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'woothee/dataset'
|
4
|
+
require 'woothee/util'
|
5
|
+
|
6
|
+
module Woothee::Browser
|
7
|
+
extend Woothee::Util
|
8
|
+
|
9
|
+
def self.challenge_msie(ua, result)
|
10
|
+
return false if ua.index("compatible; MSIE").nil?
|
11
|
+
|
12
|
+
version = if ua =~ /MSIE ([.0-9]+);/o
|
13
|
+
$1
|
14
|
+
else
|
15
|
+
Woothee::VALUE_UNKNOWN
|
16
|
+
end
|
17
|
+
update_map(result, Woothee::DataSet.get('MSIE'))
|
18
|
+
update_version(result, version)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.challenge_safari_chrome(ua, result)
|
23
|
+
return false if ua.index('Safari/').nil?
|
24
|
+
|
25
|
+
version = Woothee::VALUE_UNKNOWN
|
26
|
+
|
27
|
+
if ua =~ /(?:Chrome|CrMo)\/([.0-9]+)/o
|
28
|
+
# Chrome
|
29
|
+
version = $1
|
30
|
+
update_map(result, Woothee::DataSet.get('Chrome'))
|
31
|
+
update_version(result, version)
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Safari
|
36
|
+
if ua =~ /Version\/([.0-9]+)/o
|
37
|
+
version = $1
|
38
|
+
end
|
39
|
+
update_map(result, Woothee::DataSet.get('Safari'))
|
40
|
+
update_version(result, version)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.challenge_firefox(ua, result)
|
45
|
+
return false if ua.index('Firefox/').nil?
|
46
|
+
|
47
|
+
version = if ua =~ /Firefox\/([.0-9]+)/o
|
48
|
+
$1
|
49
|
+
else
|
50
|
+
Woothee::VALUE_UNKNOWN
|
51
|
+
end
|
52
|
+
update_map(result, Woothee::DataSet.get('Firefox'))
|
53
|
+
update_version(result, version)
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.challenge_opera(ua, result)
|
58
|
+
return false if ua.index('Opera').nil?
|
59
|
+
|
60
|
+
version = if ua =~ /Opera[\/ ]([.0-9]+)/o
|
61
|
+
$1
|
62
|
+
else
|
63
|
+
Woothee::VALUE_UNKNOWN
|
64
|
+
end
|
65
|
+
update_map(result, Woothee::DataSet.get('Opera'))
|
66
|
+
update_version(result, version)
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.challenge_sleipnir(ua, result)
|
71
|
+
return false if ua.index('Sleipnir/').nil?
|
72
|
+
|
73
|
+
version = if ua =~ /Sleipnir\/([.0-9]+)/o
|
74
|
+
$1
|
75
|
+
else
|
76
|
+
Woothee::VALUE_UNKNOWN
|
77
|
+
end
|
78
|
+
update_map(result, Woothee::DataSet.get('Sleipnir'))
|
79
|
+
update_version(result, version)
|
80
|
+
|
81
|
+
# Sleipnir's user-agent doesn't contain Windows version, so put 'Windows UNKNOWN Ver'.
|
82
|
+
# Sleipnir is IE component browser, so for Windows only.
|
83
|
+
win = Woothee::DataSet.get('Win')
|
84
|
+
update_category(result, win[Woothee::KEY_CATEGORY])
|
85
|
+
update_os(result, win[Woothee::KEY_NAME])
|
86
|
+
|
87
|
+
true
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'woothee/dataset'
|
4
|
+
require 'woothee/util'
|
5
|
+
|
6
|
+
module Woothee::Crawler
|
7
|
+
extend Woothee::Util
|
8
|
+
|
9
|
+
def self.challenge_google(ua, result)
|
10
|
+
return false if ua.index('Google').nil?
|
11
|
+
|
12
|
+
if ua.index('compatible; Googlebot')
|
13
|
+
if ua.index('compatible; Googlebot-Mobile')
|
14
|
+
update_map(result, Woothee::DataSet.get('GoogleBotMobile'))
|
15
|
+
return true
|
16
|
+
else
|
17
|
+
update_map(result, Woothee::DataSet.get('GoogleBot'))
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
if ua.index('Googlebot-Image/')
|
22
|
+
update_map(result, Woothee::DataSet.get('GoogleBot'))
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
if ua.index('Mediapartners-Google')
|
26
|
+
if ua.index('compatible; Mediapartners-Google') or ua == 'Mediapartners-Google'
|
27
|
+
update_map(result, Woothee::DataSet.get('GoogleMediaPartners'))
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
if ua.index('Feedfetcher-Google;')
|
32
|
+
update_map(result, Woothee::DataSet.get('GoogleFeedFetcher'))
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
if ua.index('AppEngine-Google')
|
36
|
+
update_map(result, Woothee::DataSet.get('GoogleAppEngine'))
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
if ua.index('Google Web Preview')
|
40
|
+
update_map(result, Woothee::DataSet.get('GoogleWebPreview'))
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.challenge_crawlers(ua, result)
|
48
|
+
if ua.index('Yahoo') or ua.index('listing.yahoo.co.jp/support/faq/')
|
49
|
+
if ua.index('compatible; Yahoo! Slurp;')
|
50
|
+
update_map(result, Woothee::DataSet.get('YahooSlurp'))
|
51
|
+
return true
|
52
|
+
end
|
53
|
+
if ua.index('YahooFeedSeekerJp') or ua.index('YahooFeedSeekerBetaJp')
|
54
|
+
update_map(result, Woothee::DataSet.get('YahooJP'))
|
55
|
+
return true
|
56
|
+
end
|
57
|
+
if ua.index('crawler (http://listing.yahoo.co.jp/support/faq/')
|
58
|
+
update_map(result, Woothee::DataSet.get('YahooJP'))
|
59
|
+
return true
|
60
|
+
end
|
61
|
+
if ua.index('Yahoo Pipes')
|
62
|
+
update_map(result, Woothee::DataSet.get('YahooPipes'))
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
if ua.index('msnbot')
|
67
|
+
update_map(result, Woothee::DataSet.get('msnbot'))
|
68
|
+
return true
|
69
|
+
end
|
70
|
+
if ua.index('bingbot')
|
71
|
+
if ua.index('compatible; bingbot')
|
72
|
+
update_map(result, Woothee::DataSet.get('bingbot'))
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
if ua.index('Baidu')
|
77
|
+
if ua.index('compatible; Baiduspider') or ua.index('Baiduspider+') or ua.index('Baiduspider-image+')
|
78
|
+
update_map(result, Woothee::DataSet.get('Baiduspider'))
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
if ua.index('Yeti')
|
83
|
+
if ua.index('http://help.naver.com/robots')
|
84
|
+
update_map(result, Woothee::DataSet.get('Yeti'))
|
85
|
+
return true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
if ua.index('FeedBurner/')
|
89
|
+
update_map(result, Woothee::DataSet.get('FeedBurner'))
|
90
|
+
return true
|
91
|
+
end
|
92
|
+
if ua.index('facebookexternalhit')
|
93
|
+
update_map(result, Woothee::DataSet.get('facebook'))
|
94
|
+
return true
|
95
|
+
end
|
96
|
+
if ua.index('ichiro')
|
97
|
+
if ua.index('http://help.goo.ne.jp/door/crawler.html') or ua.index('compatible; ichiro/mobile goo;')
|
98
|
+
update_map(result, Woothee::DataSet.get('gooIchiro'))
|
99
|
+
return true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
if ua.index('Apple-PubSub')
|
103
|
+
update_map(result, Woothee::DataSet.get('ApplePubSub'))
|
104
|
+
return true
|
105
|
+
end
|
106
|
+
if ua.index('livedoor FeedFetcher') or ua.index('Fastladder FeedFetcher')
|
107
|
+
update_map(result, Woothee::DataSet.get('livedoorFeedFetcher'))
|
108
|
+
return true
|
109
|
+
end
|
110
|
+
if ua.index('Hatena ')
|
111
|
+
if ua.index('Hatena Antenna') or ua.index('Hatena Pagetitle Agent') or ua.index('Hatena Diary RSS')
|
112
|
+
update_map(result, Woothee::DataSet.get('Hatena'))
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
if ua.index('mixi-check') or ua.index('mixi-news-crawler')
|
117
|
+
update_map(result, Woothee::DataSet.get('mixi'))
|
118
|
+
return true
|
119
|
+
end
|
120
|
+
if ua.index('Indy Library')
|
121
|
+
if ua.index('compatible; Indy Library')
|
122
|
+
update_map(result, Woothee::DataSet.get('IndyLibrary'))
|
123
|
+
return true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.challenge_maybe_crawler(ua, result)
|
131
|
+
if ua =~ /bot(?:[-_ .\/;@()]|$)/oi
|
132
|
+
update_map(result, Woothee::DataSet.get('VariousCrawler'))
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
|
136
|
+
if ua =~ /(?:Rome Client |UnwindFetchor\/|ia_archiver |Summify |PostRank\/)/o or ua.index('ASP-Ranker Feed Crawler')
|
137
|
+
update_map(result, Woothee::DataSet.get('VariousCrawler'))
|
138
|
+
return true
|
139
|
+
end
|
140
|
+
|
141
|
+
if ua =~ /(feed|web) ?parser/oi
|
142
|
+
update_map(result, Woothee::DataSet.get('VariousCrawler'))
|
143
|
+
return true
|
144
|
+
end
|
145
|
+
|
146
|
+
if ua =~ /watch ?dog/oi
|
147
|
+
update_map(result, Woothee::DataSet.get('VariousCrawler'))
|
148
|
+
return true
|
149
|
+
end
|
150
|
+
|
151
|
+
false
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Woothee
|
3
|
+
KEY_LABEL = :label
|
4
|
+
KEY_NAME = :name
|
5
|
+
KEY_TYPE = :type
|
6
|
+
KEY_CATEGORY = :category
|
7
|
+
KEY_OS = :os
|
8
|
+
KEY_VENDOR = :vendor
|
9
|
+
KEY_VERSION = :version
|
10
|
+
|
11
|
+
TYPE_BROWSER = :browser
|
12
|
+
TYPE_OS = :os
|
13
|
+
TYPE_FULL = :full
|
14
|
+
|
15
|
+
CATEGORY_PC = :pc
|
16
|
+
CATEGORY_SMARTPHONE = :smartphone
|
17
|
+
CATEGORY_MOBILEPHONE = :mobilephone
|
18
|
+
CATEGORY_CRAWLER = :crawler
|
19
|
+
CATEGORY_APPLIANCE = :appliance
|
20
|
+
CATEGORY_MISC = :misc
|
21
|
+
|
22
|
+
ATTRIBUTE_NAME = :name
|
23
|
+
ATTRIBUTE_CATEGORY = :category
|
24
|
+
ATTRIBUTE_OS = :os
|
25
|
+
ATTRIBUTE_VENDOR = :vendor
|
26
|
+
ATTRIBUTE_VERSION = :version
|
27
|
+
|
28
|
+
VALUE_UNKNOWN = "UNKNOWN"
|
29
|
+
end
|
30
|
+
|
31
|
+
module Woothee::DataSet
|
32
|
+
DATASET = {}
|
33
|
+
# GENERATED from dataset.yaml at Tue Jun 12 12:17:48 JST 2012 by tagomoris
|
34
|
+
obj = {:label => 'MSIE', :name => 'Internet Explorer', :type => :browser}
|
35
|
+
obj[:vendor] = 'Microsoft'
|
36
|
+
DATASET[obj[:label]] = obj
|
37
|
+
obj = {:label => 'Chrome', :name => 'Chrome', :type => :browser}
|
38
|
+
obj[:vendor] = 'Google'
|
39
|
+
DATASET[obj[:label]] = obj
|
40
|
+
obj = {:label => 'Safari', :name => 'Safari', :type => :browser}
|
41
|
+
obj[:vendor] = 'Apple'
|
42
|
+
DATASET[obj[:label]] = obj
|
43
|
+
obj = {:label => 'Firefox', :name => 'Firefox', :type => :browser}
|
44
|
+
obj[:vendor] = 'Mozilla'
|
45
|
+
DATASET[obj[:label]] = obj
|
46
|
+
obj = {:label => 'Opera', :name => 'Opera', :type => :browser}
|
47
|
+
obj[:vendor] = 'Opera'
|
48
|
+
DATASET[obj[:label]] = obj
|
49
|
+
obj = {:label => 'Sleipnir', :name => 'Sleipnir', :type => :browser}
|
50
|
+
obj[:vendor] = 'Fenrir Inc.'
|
51
|
+
DATASET[obj[:label]] = obj
|
52
|
+
obj = {:label => 'Win', :name => 'Windows UNKNOWN Ver', :type => :os}
|
53
|
+
obj[:category] = :pc
|
54
|
+
DATASET[obj[:label]] = obj
|
55
|
+
obj = {:label => 'Win8', :name => 'Windows 8', :type => :os}
|
56
|
+
obj[:category] = :pc
|
57
|
+
DATASET[obj[:label]] = obj
|
58
|
+
obj = {:label => 'Win7', :name => 'Windows 7', :type => :os}
|
59
|
+
obj[:category] = :pc
|
60
|
+
DATASET[obj[:label]] = obj
|
61
|
+
obj = {:label => 'WinVista', :name => 'Windows Vista', :type => :os}
|
62
|
+
obj[:category] = :pc
|
63
|
+
DATASET[obj[:label]] = obj
|
64
|
+
obj = {:label => 'WinXP', :name => 'Windows XP', :type => :os}
|
65
|
+
obj[:category] = :pc
|
66
|
+
DATASET[obj[:label]] = obj
|
67
|
+
obj = {:label => 'Win2000', :name => 'Windows 2000', :type => :os}
|
68
|
+
obj[:category] = :pc
|
69
|
+
DATASET[obj[:label]] = obj
|
70
|
+
obj = {:label => 'WinNT4', :name => 'Windows NT 4.0', :type => :os}
|
71
|
+
obj[:category] = :pc
|
72
|
+
DATASET[obj[:label]] = obj
|
73
|
+
obj = {:label => 'WinMe', :name => 'Windows Me', :type => :os}
|
74
|
+
obj[:category] = :pc
|
75
|
+
DATASET[obj[:label]] = obj
|
76
|
+
obj = {:label => 'Win98', :name => 'Windows 98', :type => :os}
|
77
|
+
obj[:category] = :pc
|
78
|
+
DATASET[obj[:label]] = obj
|
79
|
+
obj = {:label => 'Win95', :name => 'Windows 95', :type => :os}
|
80
|
+
obj[:category] = :pc
|
81
|
+
DATASET[obj[:label]] = obj
|
82
|
+
obj = {:label => 'WinPhone', :name => 'Windows Phone OS', :type => :os}
|
83
|
+
obj[:category] = :smartphone
|
84
|
+
DATASET[obj[:label]] = obj
|
85
|
+
obj = {:label => 'WinCE', :name => 'Windows CE', :type => :os}
|
86
|
+
obj[:category] = :smartphone
|
87
|
+
DATASET[obj[:label]] = obj
|
88
|
+
obj = {:label => 'OSX', :name => 'Mac OSX', :type => :os}
|
89
|
+
obj[:category] = :pc
|
90
|
+
DATASET[obj[:label]] = obj
|
91
|
+
obj = {:label => 'MacOS', :name => 'Mac OS Classic', :type => :os}
|
92
|
+
obj[:category] = :pc
|
93
|
+
DATASET[obj[:label]] = obj
|
94
|
+
obj = {:label => 'Linux', :name => 'Linux', :type => :os}
|
95
|
+
obj[:category] = :pc
|
96
|
+
DATASET[obj[:label]] = obj
|
97
|
+
obj = {:label => 'BSD', :name => 'BSD', :type => :os}
|
98
|
+
obj[:category] = :pc
|
99
|
+
DATASET[obj[:label]] = obj
|
100
|
+
obj = {:label => 'Android', :name => 'Android', :type => :os}
|
101
|
+
obj[:category] = :smartphone
|
102
|
+
DATASET[obj[:label]] = obj
|
103
|
+
obj = {:label => 'iPhone', :name => 'iPhone', :type => :os}
|
104
|
+
obj[:category] = :smartphone
|
105
|
+
DATASET[obj[:label]] = obj
|
106
|
+
obj = {:label => 'iPad', :name => 'iPad', :type => :os}
|
107
|
+
obj[:category] = :smartphone
|
108
|
+
DATASET[obj[:label]] = obj
|
109
|
+
obj = {:label => 'iPod', :name => 'iPod', :type => :os}
|
110
|
+
obj[:category] = :smartphone
|
111
|
+
DATASET[obj[:label]] = obj
|
112
|
+
obj = {:label => 'iOS', :name => 'iOS', :type => :os}
|
113
|
+
obj[:category] = :smartphone
|
114
|
+
DATASET[obj[:label]] = obj
|
115
|
+
obj = {:label => 'BlackBerry', :name => 'BlackBerry', :type => :os}
|
116
|
+
obj[:category] = :smartphone
|
117
|
+
DATASET[obj[:label]] = obj
|
118
|
+
obj = {:label => 'docomo', :name => 'docomo', :type => :full}
|
119
|
+
obj[:vendor] = 'docomo'
|
120
|
+
obj[:category] = :mobilephone
|
121
|
+
obj[:os] = 'docomo'
|
122
|
+
DATASET[obj[:label]] = obj
|
123
|
+
obj = {:label => 'au', :name => 'au by KDDI', :type => :full}
|
124
|
+
obj[:vendor] = 'au'
|
125
|
+
obj[:category] = :mobilephone
|
126
|
+
obj[:os] = 'au'
|
127
|
+
DATASET[obj[:label]] = obj
|
128
|
+
obj = {:label => 'SoftBank', :name => 'SoftBank Mobile', :type => :full}
|
129
|
+
obj[:vendor] = 'SoftBank'
|
130
|
+
obj[:category] = :mobilephone
|
131
|
+
obj[:os] = 'SoftBank'
|
132
|
+
DATASET[obj[:label]] = obj
|
133
|
+
obj = {:label => 'willcom', :name => 'WILLCOM', :type => :full}
|
134
|
+
obj[:vendor] = 'WILLCOM'
|
135
|
+
obj[:category] = :mobilephone
|
136
|
+
obj[:os] = 'WILLCOM'
|
137
|
+
DATASET[obj[:label]] = obj
|
138
|
+
obj = {:label => 'jig', :name => 'jig browser', :type => :full}
|
139
|
+
obj[:category] = :mobilephone
|
140
|
+
obj[:os] = 'jig'
|
141
|
+
DATASET[obj[:label]] = obj
|
142
|
+
obj = {:label => 'emobile', :name => 'emobile', :type => :full}
|
143
|
+
obj[:category] = :mobilephone
|
144
|
+
obj[:os] = 'emobile'
|
145
|
+
DATASET[obj[:label]] = obj
|
146
|
+
obj = {:label => 'SymbianOS', :name => 'SymbianOS', :type => :full}
|
147
|
+
obj[:category] = :mobilephone
|
148
|
+
obj[:os] = 'SymbianOS'
|
149
|
+
DATASET[obj[:label]] = obj
|
150
|
+
obj = {:label => 'MobileTranscoder', :name => 'Mobile Transcoder', :type => :full}
|
151
|
+
obj[:category] = :mobilephone
|
152
|
+
obj[:os] = 'Mobile Transcoder'
|
153
|
+
DATASET[obj[:label]] = obj
|
154
|
+
obj = {:label => 'Nintendo3DS', :name => 'Nintendo 3DS', :type => :full}
|
155
|
+
obj[:vendor] = 'Nintendo'
|
156
|
+
obj[:category] = :appliance
|
157
|
+
obj[:os] = 'Nintendo 3DS'
|
158
|
+
DATASET[obj[:label]] = obj
|
159
|
+
obj = {:label => 'NintendoDSi', :name => 'Nintendo DSi', :type => :full}
|
160
|
+
obj[:vendor] = 'Nintendo'
|
161
|
+
obj[:category] = :appliance
|
162
|
+
obj[:os] = 'Nintendo DSi'
|
163
|
+
DATASET[obj[:label]] = obj
|
164
|
+
obj = {:label => 'NintendoWii', :name => 'Nintendo Wii', :type => :full}
|
165
|
+
obj[:vendor] = 'Nintendo'
|
166
|
+
obj[:category] = :appliance
|
167
|
+
obj[:os] = 'Nintendo Wii'
|
168
|
+
DATASET[obj[:label]] = obj
|
169
|
+
obj = {:label => 'PSP', :name => 'PlayStation Portable', :type => :full}
|
170
|
+
obj[:vendor] = 'Sony'
|
171
|
+
obj[:category] = :appliance
|
172
|
+
obj[:os] = 'PlayStation Portable'
|
173
|
+
DATASET[obj[:label]] = obj
|
174
|
+
obj = {:label => 'PSVita', :name => 'PlayStation Vita', :type => :full}
|
175
|
+
obj[:vendor] = 'Sony'
|
176
|
+
obj[:category] = :appliance
|
177
|
+
obj[:os] = 'PlayStation Vita'
|
178
|
+
DATASET[obj[:label]] = obj
|
179
|
+
obj = {:label => 'PS3', :name => 'PlayStation 3', :type => :full}
|
180
|
+
obj[:vendor] = 'Sony'
|
181
|
+
obj[:category] = :appliance
|
182
|
+
obj[:os] = 'PlayStation 3'
|
183
|
+
DATASET[obj[:label]] = obj
|
184
|
+
obj = {:label => 'DigitalTV', :name => 'InternetTVBrowser', :type => :full}
|
185
|
+
obj[:category] = :appliance
|
186
|
+
obj[:os] = 'DigitalTV'
|
187
|
+
DATASET[obj[:label]] = obj
|
188
|
+
obj = {:label => 'SafariRSSReader', :name => 'Safari RSSReader', :type => :full}
|
189
|
+
obj[:vendor] = 'Apple'
|
190
|
+
obj[:category] = :misc
|
191
|
+
DATASET[obj[:label]] = obj
|
192
|
+
obj = {:label => 'GoogleDesktop', :name => 'Google Desktop', :type => :full}
|
193
|
+
obj[:vendor] = 'Google'
|
194
|
+
obj[:category] = :misc
|
195
|
+
DATASET[obj[:label]] = obj
|
196
|
+
obj = {:label => 'WindowsRSSReader', :name => 'Windows RSSReader', :type => :full}
|
197
|
+
obj[:vendor] = 'Microsoft'
|
198
|
+
obj[:category] = :misc
|
199
|
+
DATASET[obj[:label]] = obj
|
200
|
+
obj = {:label => 'VariousRSSReader', :name => 'RSSReader', :type => :full}
|
201
|
+
obj[:category] = :misc
|
202
|
+
DATASET[obj[:label]] = obj
|
203
|
+
obj = {:label => 'HTTPLibrary', :name => 'HTTP Library', :type => :full}
|
204
|
+
obj[:category] = :misc
|
205
|
+
DATASET[obj[:label]] = obj
|
206
|
+
obj = {:label => 'GoogleBot', :name => 'Googlebot', :type => :full}
|
207
|
+
obj[:category] = :crawler
|
208
|
+
DATASET[obj[:label]] = obj
|
209
|
+
obj = {:label => 'GoogleBotMobile', :name => 'Googlebot Mobile', :type => :full}
|
210
|
+
obj[:category] = :crawler
|
211
|
+
DATASET[obj[:label]] = obj
|
212
|
+
obj = {:label => 'GoogleMediaPartners', :name => 'Google Mediapartners', :type => :full}
|
213
|
+
obj[:category] = :crawler
|
214
|
+
DATASET[obj[:label]] = obj
|
215
|
+
obj = {:label => 'GoogleFeedFetcher', :name => 'Google Feedfetcher', :type => :full}
|
216
|
+
obj[:category] = :crawler
|
217
|
+
DATASET[obj[:label]] = obj
|
218
|
+
obj = {:label => 'GoogleAppEngine', :name => 'Google AppEngine', :type => :full}
|
219
|
+
obj[:category] = :crawler
|
220
|
+
DATASET[obj[:label]] = obj
|
221
|
+
obj = {:label => 'GoogleWebPreview', :name => 'Google Web Preview', :type => :full}
|
222
|
+
obj[:category] = :crawler
|
223
|
+
DATASET[obj[:label]] = obj
|
224
|
+
obj = {:label => 'YahooSlurp', :name => 'Yahoo! Slurp', :type => :full}
|
225
|
+
obj[:category] = :crawler
|
226
|
+
DATASET[obj[:label]] = obj
|
227
|
+
obj = {:label => 'YahooJP', :name => 'Yahoo! Japan', :type => :full}
|
228
|
+
obj[:category] = :crawler
|
229
|
+
DATASET[obj[:label]] = obj
|
230
|
+
obj = {:label => 'YahooPipes', :name => 'Yahoo! Pipes', :type => :full}
|
231
|
+
obj[:category] = :crawler
|
232
|
+
DATASET[obj[:label]] = obj
|
233
|
+
obj = {:label => 'Baiduspider', :name => 'Baiduspider', :type => :full}
|
234
|
+
obj[:category] = :crawler
|
235
|
+
DATASET[obj[:label]] = obj
|
236
|
+
obj = {:label => 'msnbot', :name => 'msnbot', :type => :full}
|
237
|
+
obj[:category] = :crawler
|
238
|
+
DATASET[obj[:label]] = obj
|
239
|
+
obj = {:label => 'bingbot', :name => 'bingbot', :type => :full}
|
240
|
+
obj[:category] = :crawler
|
241
|
+
DATASET[obj[:label]] = obj
|
242
|
+
obj = {:label => 'Yeti', :name => 'Naver Yeti', :type => :full}
|
243
|
+
obj[:category] = :crawler
|
244
|
+
DATASET[obj[:label]] = obj
|
245
|
+
obj = {:label => 'FeedBurner', :name => 'Google FeedBurner', :type => :full}
|
246
|
+
obj[:category] = :crawler
|
247
|
+
DATASET[obj[:label]] = obj
|
248
|
+
obj = {:label => 'facebook', :name => 'facebook', :type => :full}
|
249
|
+
obj[:category] = :crawler
|
250
|
+
DATASET[obj[:label]] = obj
|
251
|
+
obj = {:label => 'mixi', :name => 'mixi', :type => :full}
|
252
|
+
obj[:category] = :crawler
|
253
|
+
DATASET[obj[:label]] = obj
|
254
|
+
obj = {:label => 'IndyLibrary', :name => 'Indy Library', :type => :full}
|
255
|
+
obj[:category] = :crawler
|
256
|
+
DATASET[obj[:label]] = obj
|
257
|
+
obj = {:label => 'ApplePubSub', :name => 'Apple iCloud', :type => :full}
|
258
|
+
obj[:category] = :crawler
|
259
|
+
DATASET[obj[:label]] = obj
|
260
|
+
obj = {:label => 'Hatena', :name => 'Hatena', :type => :full}
|
261
|
+
obj[:category] = :crawler
|
262
|
+
DATASET[obj[:label]] = obj
|
263
|
+
obj = {:label => 'gooIchiro', :name => 'goo', :type => :full}
|
264
|
+
obj[:category] = :crawler
|
265
|
+
DATASET[obj[:label]] = obj
|
266
|
+
obj = {:label => 'livedoorFeedFetcher', :name => 'livedoor FeedFetcher', :type => :full}
|
267
|
+
obj[:category] = :crawler
|
268
|
+
DATASET[obj[:label]] = obj
|
269
|
+
obj = {:label => 'VariousCrawler', :name => 'misc crawler', :type => :full}
|
270
|
+
obj[:category] = :crawler
|
271
|
+
DATASET[obj[:label]] = obj
|
272
|
+
|
273
|
+
DATASET.freeze
|
274
|
+
|
275
|
+
def self.get(label)
|
276
|
+
DATASET[label]
|
277
|
+
end
|
278
|
+
end
|
data/lib/woothee/misc.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'woothee/dataset'
|
4
|
+
require 'woothee/util'
|
5
|
+
|
6
|
+
module Woothee::Misc
|
7
|
+
extend Woothee::Util
|
8
|
+
|
9
|
+
def self.challenge_desktoptools(ua, result)
|
10
|
+
data = case
|
11
|
+
when ua.index('AppleSyndication/') then Woothee::DataSet.get('SafariRSSReader')
|
12
|
+
when ua.index('compatible; Google Desktop/') then Woothee::DataSet.get('GoogleDesktop')
|
13
|
+
when ua.index('Windows-RSS-Platform') then Woothee::DataSet.get('WindowsRSSReader')
|
14
|
+
else nil
|
15
|
+
end
|
16
|
+
return false unless data
|
17
|
+
|
18
|
+
update_map(result, data)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.challenge_smartphone_patterns(ua, result)
|
23
|
+
if ua.index('CFNetwork/')
|
24
|
+
data = Woothee::DataSet.get('iOS')
|
25
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
26
|
+
update_os(result, data[Woothee::KEY_NAME])
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.challenge_http_library(ua, result)
|
34
|
+
data,version = case
|
35
|
+
when ua =~ /^(?:Apache-HttpClient\/|Jakarta Commons-HttpClient\/|Java\/)/o
|
36
|
+
[Woothee::DataSet.get('HTTPLibrary'), 'Java']
|
37
|
+
when ua =~ /^Wget/o
|
38
|
+
[Woothee::DataSet.get('HTTPLibrary'), 'wget']
|
39
|
+
when ua =~ /^(?:libwww-perl|WWW-Mechanize|LWP::Simple|LWP |lwp-trivial)/o
|
40
|
+
[Woothee::DataSet.get('HTTPLibrary'), 'perl']
|
41
|
+
when ua =~ /^Python-urllib\//o
|
42
|
+
[Woothee::DataSet.get('HTTPLibrary'), 'python']
|
43
|
+
when ua =~ /^(:?PHP\/|WordPress\/|CakePHP|PukiWiki\/)/o
|
44
|
+
[Woothee::DataSet.get('HTTPLibrary'), 'php']
|
45
|
+
when ua.index('PEAR HTTP_Request class;')
|
46
|
+
[Woothee::DataSet.get('HTTPLibrary'), 'php']
|
47
|
+
else [nil,nil]
|
48
|
+
end
|
49
|
+
return false unless data
|
50
|
+
|
51
|
+
update_map(result, data)
|
52
|
+
update_version(result, version)
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.challenge_maybe_rss_reader(ua, result)
|
57
|
+
data = if ua =~ /rss(?:reader|bar|[-_ \/;()])/oi
|
58
|
+
Woothee::DataSet.get('VariousRSSReader')
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
return false unless data
|
63
|
+
|
64
|
+
update_map(result, data)
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'woothee/dataset'
|
4
|
+
require 'woothee/util'
|
5
|
+
|
6
|
+
module Woothee::MobilePhone
|
7
|
+
extend Woothee::Util
|
8
|
+
|
9
|
+
def self.challenge_docomo(ua, result)
|
10
|
+
return false if ua.index('DoCoMo').nil? and ua.index(';FOMA;').nil?
|
11
|
+
|
12
|
+
version = if ua =~ /DoCoMo\/[.0-9]+[ \/]([^- \/;()"']+)/o
|
13
|
+
$1
|
14
|
+
elsif ua =~ /\(([^;)]+);FOMA;/o
|
15
|
+
$1
|
16
|
+
else
|
17
|
+
Woothee::VALUE_UNKNOWN
|
18
|
+
end
|
19
|
+
update_map(result, Woothee::DataSet.get('docomo'))
|
20
|
+
update_version(result, version)
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.challenge_au(ua, result)
|
25
|
+
return false if ua.index('KDDI-').nil?
|
26
|
+
|
27
|
+
# fix Woothee::OS.challenge_mobile if you want to fix here
|
28
|
+
version = if ua =~ /KDDI-([^- \/;()"']+)/o
|
29
|
+
$1
|
30
|
+
else
|
31
|
+
Woothee::VALUE_UNKNOWN
|
32
|
+
end
|
33
|
+
update_map(result, Woothee::DataSet.get('au'))
|
34
|
+
update_version(result, version)
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.challenge_softbank(ua, result)
|
39
|
+
return false if ua.index('SoftBank').nil? and ua.index('Vodafone').nil? and ua.index('J-PHONE').nil?
|
40
|
+
|
41
|
+
version = if ua =~ /(?:SoftBank|Vodafone|J-PHONE)\/[.0-9]+\/([^ \/;()]+)/o
|
42
|
+
$1
|
43
|
+
else
|
44
|
+
Woothee::VALUE_UNKNOWN
|
45
|
+
end
|
46
|
+
update_map(result, Woothee::DataSet.get('SoftBank'))
|
47
|
+
update_version(result, version)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.challenge_willcom(ua, result)
|
52
|
+
return false if ua.index('WILLCOM').nil? and ua.index('DDIPOCKET').nil?
|
53
|
+
|
54
|
+
# fix Woothee::OS.challenge_mobile if you want to fix here
|
55
|
+
version = if ua =~ /(?:WILLCOM|DDIPOCKET);[^\/]+\/([^ \/;()]+)/o
|
56
|
+
$1
|
57
|
+
else
|
58
|
+
Woothee::VALUE_UNKNOWN
|
59
|
+
end
|
60
|
+
update_map(result, Woothee::DataSet.get('willcom'))
|
61
|
+
update_version(result, version)
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.challenge_misc(ua, result)
|
66
|
+
if ua.index('jig browser')
|
67
|
+
update_map(result, Woothee::DataSet.get('jig'))
|
68
|
+
if ua =~ /jig browser[^;]+; ([^);]+)/o
|
69
|
+
update_version(result, $1)
|
70
|
+
end
|
71
|
+
return true
|
72
|
+
end
|
73
|
+
if ua.index('emobile/') or ua.index('OpenBrowser') or ua.index('Browser/Obigo-Browser')
|
74
|
+
update_map(result, Woothee::DataSet.get('emobile'))
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
if ua.index('SymbianOS')
|
78
|
+
update_map(result, Woothee::DataSet.get('SymbianOS'))
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
if ua.index('Hatena-Mobile-Gateway/')
|
82
|
+
update_map(result, Woothee::DataSet.get('MobileTranscoder'))
|
83
|
+
update_version(result, 'Hatena')
|
84
|
+
return true
|
85
|
+
end
|
86
|
+
if ua.index('livedoor-Mobile-Gateway/')
|
87
|
+
update_map(result, Woothee::DataSet.get('MobileTranscoder'))
|
88
|
+
update_version(result, 'livedoor')
|
89
|
+
return true
|
90
|
+
end
|
91
|
+
|
92
|
+
false
|
93
|
+
end
|
94
|
+
end
|
data/lib/woothee/os.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'woothee/dataset'
|
4
|
+
require 'woothee/util'
|
5
|
+
|
6
|
+
module Woothee::OS
|
7
|
+
extend Woothee::Util
|
8
|
+
|
9
|
+
def self.challenge_windows(ua, result)
|
10
|
+
return false if ua.index("Windows").nil?
|
11
|
+
|
12
|
+
data = Woothee::DataSet.get('Win')
|
13
|
+
unless ua =~ /Windows ([ .a-zA-Z0-9]+)[;\\)]/o
|
14
|
+
# Windows, but version unknown
|
15
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
16
|
+
update_os(result, data[Woothee::KEY_NAME])
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
|
20
|
+
version = $1
|
21
|
+
data = case
|
22
|
+
when version == 'NT 6.2' then Woothee::DataSet.get('Win8')
|
23
|
+
when version == 'NT 6.1' then Woothee::DataSet.get('Win7')
|
24
|
+
when version == 'NT 6.0' then Woothee::DataSet.get('WinVista')
|
25
|
+
when version == 'NT 5.1' then Woothee::DataSet.get('WinXP')
|
26
|
+
when version =~ /^Phone OS/o then Woothee::DataSet.get('WinPhone')
|
27
|
+
when version == 'NT 5.0' then Woothee::DataSet.get('Win2000')
|
28
|
+
when version == 'NT 4.0' then Woothee::DataSet.get('WinNT4')
|
29
|
+
when version == '98' then Woothee::DataSet.get('Win98') # wow, WinMe is shown as 'Windows 98; Win9x 4.90', fxxxk
|
30
|
+
when version == '95' then Woothee::DataSet.get('Win95')
|
31
|
+
when version == 'CE' then Woothee::DataSet.get('WinCE')
|
32
|
+
else
|
33
|
+
data # windows unknown version
|
34
|
+
end
|
35
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
36
|
+
update_os(result, data[Woothee::KEY_NAME])
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.challenge_osx(ua, result)
|
41
|
+
return false if ua.index('Mac OS X').nil?
|
42
|
+
|
43
|
+
data = Woothee::DataSet.get('OSX')
|
44
|
+
if ua.index('like Mac OS X')
|
45
|
+
data = case
|
46
|
+
when ua.index('iPhone;') then Woothee::DataSet.get('iPhone')
|
47
|
+
when ua.index('iPad;') then Woothee::DataSet.get('iPad')
|
48
|
+
when ua.index('iPod;') then Woothee::DataSet.get('iPod')
|
49
|
+
else data
|
50
|
+
end
|
51
|
+
end
|
52
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
53
|
+
update_os(result, data[Woothee::KEY_NAME])
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.challenge_linux(ua, result)
|
58
|
+
return false if ua.index('Linux').nil?
|
59
|
+
|
60
|
+
data = if ua.index('Android')
|
61
|
+
Woothee::DataSet.get('Android')
|
62
|
+
else
|
63
|
+
Woothee::DataSet.get('Linux')
|
64
|
+
end
|
65
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
66
|
+
update_os(result, data[Woothee::KEY_NAME])
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.challenge_smartphone(ua, result)
|
71
|
+
data = case
|
72
|
+
when ua.index('iPhone') then Woothee::DataSet.get('iPhone')
|
73
|
+
when ua.index('iPad') then Woothee::DataSet.get('iPad')
|
74
|
+
when ua.index('iPod') then Woothee::DataSet.get('iPod')
|
75
|
+
when ua.index('Android') then Woothee::DataSet.get('Android')
|
76
|
+
when ua.index('CFNetwork') then Woothee::DataSet.get('iOS')
|
77
|
+
when ua.index('BlackBerry') then Woothee::DataSet.get('BlackBerry')
|
78
|
+
else nil
|
79
|
+
end
|
80
|
+
return false unless data
|
81
|
+
|
82
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
83
|
+
update_os(result, data[Woothee::KEY_NAME])
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.challenge_mobilephone(ua, result)
|
88
|
+
if ua.index('KDDI-')
|
89
|
+
if ua =~ /KDDI-([^- \/;()"']+)/o
|
90
|
+
term = $1
|
91
|
+
data = Woothee::DataSet.get('au')
|
92
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
93
|
+
update_os(result, data[Woothee::KEY_OS])
|
94
|
+
update_version(result, term)
|
95
|
+
return true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
if ua.index('WILLCOM') or ua.index('DDIPOCKET')
|
99
|
+
if ua =~ /(?:WILLCOM|DDIPOCKET);[^\/]+\/([^ \/;()]+)/o
|
100
|
+
term = $1
|
101
|
+
data = Woothee::DataSet.get('willcom')
|
102
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
103
|
+
update_os(result, data[Woothee::KEY_OS])
|
104
|
+
update_version(result, term)
|
105
|
+
return true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
if ua.index('SymbianOS')
|
109
|
+
data = Woothee::DataSet.get('SymbianOS')
|
110
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
111
|
+
update_os(result, data[Woothee::KEY_OS])
|
112
|
+
return true
|
113
|
+
end
|
114
|
+
if ua.index('Google Wireless Transcoder')
|
115
|
+
update_map(result, Woothee::DataSet.get('MobileTranscoder'))
|
116
|
+
update_version(result, 'Google')
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
if ua.index('Naver Transcoder')
|
120
|
+
update_map(result, Woothee::DataSet.get('MobileTranscoder'))
|
121
|
+
update_version(result, 'Naver')
|
122
|
+
return true
|
123
|
+
end
|
124
|
+
|
125
|
+
false
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.challenge_appliance(ua, result)
|
129
|
+
if ua.index('Nintendo DSi;')
|
130
|
+
data = Woothee::DataSet.get('NintendoDSi')
|
131
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
132
|
+
update_os(result, data[Woothee::KEY_OS])
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
if ua.index('Nintendo Wii;')
|
136
|
+
data = Woothee::DataSet.get('NintendoWii')
|
137
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
138
|
+
update_os(result, data[Woothee::KEY_OS])
|
139
|
+
return true
|
140
|
+
end
|
141
|
+
|
142
|
+
false
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.challenge_misc(ua, result)
|
146
|
+
data = case
|
147
|
+
when ua.index('(Win98;')
|
148
|
+
Woothee::DataSet.get('Win98')
|
149
|
+
when ua.index('Macintosh; U; PPC;')
|
150
|
+
Woothee::DataSet.get('MacOS')
|
151
|
+
when ua.index('Mac_PowerPC')
|
152
|
+
Woothee::DataSet.get('MacOS')
|
153
|
+
when ua.index('X11; FreeBSD ')
|
154
|
+
Woothee::DataSet.get('BSD')
|
155
|
+
else
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
if data
|
159
|
+
update_category(result, data[Woothee::KEY_CATEGORY])
|
160
|
+
update_os(result, data[Woothee::KEY_NAME])
|
161
|
+
return true
|
162
|
+
end
|
163
|
+
|
164
|
+
false
|
165
|
+
end
|
166
|
+
end
|
data/lib/woothee/util.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Woothee::Util
|
4
|
+
def update_map(target, source)
|
5
|
+
source.keys.each do |key|
|
6
|
+
next if key == Woothee::KEY_LABEL or key == Woothee::KEY_TYPE
|
7
|
+
if source[key].length > 0
|
8
|
+
target[key] = source[key]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_category(target, category)
|
14
|
+
target[Woothee::ATTRIBUTE_CATEGORY] = category
|
15
|
+
end
|
16
|
+
|
17
|
+
def update_version(target, version)
|
18
|
+
target[Woothee::ATTRIBUTE_VERSION] = version
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_os(target, os)
|
22
|
+
target[Woothee::ATTRIBUTE_OS] = os
|
23
|
+
end
|
24
|
+
end
|
data/lib/woothee.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'woothee/dataset'
|
4
|
+
require 'woothee/browser'
|
5
|
+
require 'woothee/os'
|
6
|
+
require 'woothee/mobilephone'
|
7
|
+
require 'woothee/crawler'
|
8
|
+
require 'woothee/appliance'
|
9
|
+
require 'woothee/misc'
|
10
|
+
|
11
|
+
module Woothee
|
12
|
+
def self.parse(useragent)
|
13
|
+
fill_result(exec_parse(useragent))
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.is_crawler(useragent)
|
17
|
+
useragent.length > 0 and useragent != '-' and try_crawler(useragent, {})
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.exec_parse(useragent)
|
21
|
+
result = {}
|
22
|
+
|
23
|
+
return result if useragent.length < 1 or useragent == '-'
|
24
|
+
|
25
|
+
if try_crawler(useragent, result)
|
26
|
+
return result
|
27
|
+
end
|
28
|
+
|
29
|
+
if try_browser(useragent, result)
|
30
|
+
if try_os(useragent, result)
|
31
|
+
return result
|
32
|
+
else
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
if try_mobilephone(useragent, result)
|
38
|
+
return result
|
39
|
+
end
|
40
|
+
|
41
|
+
if try_appliance(useragent, result)
|
42
|
+
return result
|
43
|
+
end
|
44
|
+
|
45
|
+
if try_misc(useragent, result)
|
46
|
+
return result
|
47
|
+
end
|
48
|
+
|
49
|
+
# browser unknown. check os only
|
50
|
+
if try_os(useragent, result)
|
51
|
+
return result
|
52
|
+
end
|
53
|
+
|
54
|
+
if try_rare_cases(useragent, result)
|
55
|
+
return result
|
56
|
+
end
|
57
|
+
|
58
|
+
result
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.try_crawler(useragent, result)
|
62
|
+
return true if Woothee::Crawler.challenge_google(useragent, result)
|
63
|
+
|
64
|
+
return true if Woothee::Crawler.challenge_crawlers(useragent, result)
|
65
|
+
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.try_browser(useragent, result)
|
70
|
+
return true if Woothee::Browser.challenge_msie(useragent, result)
|
71
|
+
|
72
|
+
return true if Woothee::Browser.challenge_safari_chrome(useragent, result)
|
73
|
+
|
74
|
+
return true if Woothee::Browser.challenge_firefox(useragent, result)
|
75
|
+
|
76
|
+
return true if Woothee::Browser.challenge_opera(useragent, result)
|
77
|
+
|
78
|
+
false
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.try_os(useragent, result)
|
82
|
+
return true if Woothee::OS.challenge_windows(useragent, result)
|
83
|
+
|
84
|
+
# OSX PC and iOS devices (strict check)
|
85
|
+
return true if Woothee::OS.challenge_osx(useragent, result)
|
86
|
+
|
87
|
+
# Linux PC and Android
|
88
|
+
return true if Woothee::OS.challenge_linux(useragent, result)
|
89
|
+
|
90
|
+
# all useragents matches /(iPhone|iPad|iPod|Android|BlackBerry)/
|
91
|
+
return true if Woothee::OS.challenge_smartphone(useragent, result)
|
92
|
+
|
93
|
+
# mobile phones like KDDI-.*
|
94
|
+
return true if Woothee::OS.challenge_mobilephone(useragent, result)
|
95
|
+
|
96
|
+
# Nintendo DSi/Wii with Opera
|
97
|
+
return true if Woothee::OS.challenge_appliance(useragent, result)
|
98
|
+
|
99
|
+
# Win98, BSD, classic MacOS, ...
|
100
|
+
return true if Woothee::OS.challenge_misc(useragent, result)
|
101
|
+
|
102
|
+
false
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.try_mobilephone(useragent, result)
|
106
|
+
return true if Woothee::MobilePhone.challenge_docomo(useragent, result)
|
107
|
+
|
108
|
+
return true if Woothee::MobilePhone.challenge_au(useragent, result)
|
109
|
+
|
110
|
+
return true if Woothee::MobilePhone.challenge_softbank(useragent, result)
|
111
|
+
|
112
|
+
return true if Woothee::MobilePhone.challenge_willcom(useragent, result)
|
113
|
+
|
114
|
+
return true if Woothee::MobilePhone.challenge_misc(useragent, result)
|
115
|
+
|
116
|
+
false
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.try_appliance(useragent, result)
|
120
|
+
return true if Woothee::Appliance.challenge_playstation(useragent, result)
|
121
|
+
|
122
|
+
return true if Woothee::Appliance.challenge_nintendo(useragent, result)
|
123
|
+
|
124
|
+
return true if Woothee::Appliance.challenge_digitaltv(useragent, result)
|
125
|
+
|
126
|
+
false
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.try_misc(useragent, result)
|
130
|
+
return true if Woothee::Misc.challenge_desktoptools(useragent, result)
|
131
|
+
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.try_rare_cases(useragent, result)
|
136
|
+
return true if Woothee::Misc.challenge_smartphone_patterns(useragent, result)
|
137
|
+
|
138
|
+
return true if Woothee::Browser.challenge_sleipnir(useragent, result)
|
139
|
+
|
140
|
+
return true if Woothee::Misc.challenge_http_library(useragent, result)
|
141
|
+
|
142
|
+
return true if Woothee::Misc.challenge_maybe_rss_reader(useragent, result)
|
143
|
+
|
144
|
+
return true if Woothee::Crawler.challenge_maybe_crawler(useragent, result)
|
145
|
+
|
146
|
+
false
|
147
|
+
end
|
148
|
+
|
149
|
+
FILLED = {
|
150
|
+
Woothee::ATTRIBUTE_NAME => Woothee::VALUE_UNKNOWN,
|
151
|
+
Woothee::ATTRIBUTE_CATEGORY => Woothee::VALUE_UNKNOWN,
|
152
|
+
Woothee::ATTRIBUTE_OS => Woothee::VALUE_UNKNOWN,
|
153
|
+
Woothee::ATTRIBUTE_VERSION => Woothee::VALUE_UNKNOWN,
|
154
|
+
Woothee::ATTRIBUTE_VENDOR => Woothee::VALUE_UNKNOWN,
|
155
|
+
}.freeze
|
156
|
+
def self.fill_result(result)
|
157
|
+
FILLED.merge(result)
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
$LOAD_PATH.push '../lib' unless $LOAD_PATH.include?('../lib')
|
4
|
+
|
5
|
+
module Woothee
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Woothee do
|
9
|
+
it "should be read from each modules correctly" do
|
10
|
+
lambda { require 'woothee/dataset' }.should_not raise_error(LoadError)
|
11
|
+
lambda { require 'woothee' }.should_not raise_error(LoadError)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
$LOAD_PATH.push '../lib' unless $LOAD_PATH.include?('../lib')
|
4
|
+
|
5
|
+
require 'woothee/dataset'
|
6
|
+
|
7
|
+
describe Woothee::DataSet do
|
8
|
+
it "contains constants" do
|
9
|
+
lambda { Woothee::ATTRIBUTE_NAME }.should_not raise_error(NameError)
|
10
|
+
Woothee::ATTRIBUTE_NAME.should eql(:name)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "contains dataset" do
|
14
|
+
Woothee::DataSet.get('GoogleBot')[:name].should eql('Googlebot')
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
$LOAD_PATH.push '../lib' unless $LOAD_PATH.include?('../lib')
|
4
|
+
|
5
|
+
require 'yaml'
|
6
|
+
require 'woothee'
|
7
|
+
|
8
|
+
TESTSET_DIR = File.dirname(__FILE__) + "/../../testsets/";
|
9
|
+
|
10
|
+
TARGETS = [
|
11
|
+
['crawler.yaml','Crawler'],['crawler_google.yaml','Crawler/Google'],
|
12
|
+
['pc_windows.yaml','PC/Windows'],['pc_misc.yaml','PC/Misc'],
|
13
|
+
['mobilephone_docomo.yaml','MobilePhone/docomo'],['mobilephone_au.yaml','MobilePhone/au'],
|
14
|
+
['mobilephone_softbank.yaml','MobilePhone/softbank'],['mobilephone_willcom.yaml','MobilePhone/willcom'],
|
15
|
+
['mobilephone_misc.yaml','MobilePhone/misc'],
|
16
|
+
['smartphone_ios.yaml','SmartPhone/ios'],['smartphone_android.yaml','SmartPhone/android'],
|
17
|
+
['smartphone_misc.yaml','SmartPhone/misc'],
|
18
|
+
['appliance.yaml','Appliance'],
|
19
|
+
['pc_lowpriority.yaml','PC/LowPriority'],
|
20
|
+
['misc.yaml','Misc'],
|
21
|
+
['crawler_nonmajor.yaml','Crawler/NonMajor'],
|
22
|
+
]
|
23
|
+
|
24
|
+
describe Woothee do
|
25
|
+
|
26
|
+
TARGETS.each do |filename,groupname|
|
27
|
+
YAML.load_file(TESTSET_DIR + filename).each do |e|
|
28
|
+
r = Woothee.parse(e['target'])
|
29
|
+
[:name, :category, :os, :version, :vendor].each do |attribute|
|
30
|
+
it groupname + ("test(%s): %s" % [attribute, e['target']]) do
|
31
|
+
if [:name, :category].include?(attribute) or ([:os, :version, :vendor].include?(attribute) and e.has_key?(attribute.to_s))
|
32
|
+
r[attribute].to_s.should eql(e[attribute.to_s])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/woothee.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# $:.push File.expand_path('../lib', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "woothee"
|
6
|
+
gem.description = "Cross-language UserAgent classifier library, ruby implementation"
|
7
|
+
gem.homepage = "https://github.com/tagomoris/woothee"
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.version = "0.2.0"
|
10
|
+
gem.authors = ["TAGOMORI Satoshi"]
|
11
|
+
gem.email = "tagomoris@gmail.com"
|
12
|
+
gem.has_rdoc = false
|
13
|
+
#gem.platform = Gem::Platform::RUBY
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
15
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
gem.require_paths = ['lib']
|
18
|
+
|
19
|
+
gem.add_development_dependency "rspec", ">= 2.8.0"
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: woothee
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- TAGOMORI Satoshi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.8.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.8.0
|
30
|
+
description: Cross-language UserAgent classifier library, ruby implementation
|
31
|
+
email: tagomoris@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- Gemfile
|
37
|
+
- Makefile
|
38
|
+
- Rakefile
|
39
|
+
- lib/woothee.rb
|
40
|
+
- lib/woothee/appliance.rb
|
41
|
+
- lib/woothee/browser.rb
|
42
|
+
- lib/woothee/crawler.rb
|
43
|
+
- lib/woothee/dataset.rb
|
44
|
+
- lib/woothee/misc.rb
|
45
|
+
- lib/woothee/mobilephone.rb
|
46
|
+
- lib/woothee/os.rb
|
47
|
+
- lib/woothee/util.rb
|
48
|
+
- spec/00_valid_spec.rb
|
49
|
+
- spec/01_dataset_spec.rb
|
50
|
+
- spec/02_run_testsets_spec.rb
|
51
|
+
- woothee.gemspec
|
52
|
+
homepage: https://github.com/tagomoris/woothee
|
53
|
+
licenses: []
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.8.21
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Cross-language UserAgent classifier library, ruby implementation
|
76
|
+
test_files:
|
77
|
+
- spec/00_valid_spec.rb
|
78
|
+
- spec/01_dataset_spec.rb
|
79
|
+
- spec/02_run_testsets_spec.rb
|