├── lib ├── device_detector │ ├── version.rb │ ├── bot.rb │ ├── version_extractor.rb │ ├── name_extractor.rb │ ├── client.rb │ ├── model_extractor.rb │ ├── metadata_extractor.rb │ ├── memory_cache.rb │ ├── parser.rb │ ├── device.rb │ └── os.rb └── device_detector.rb ├── .gitignore ├── spec ├── fixtures │ ├── device │ │ ├── car_browser.yml │ │ ├── camera.yml │ │ └── console.yml │ ├── detector │ │ ├── car_browser.yml │ │ ├── smart_display.yml │ │ ├── camera.yml │ │ ├── mobile_apps.yml │ │ ├── portable_media_player.yml │ │ ├── mediaplayer.yml │ │ ├── console.yml │ │ ├── tablet-2.yml │ │ ├── feed_reader.yml │ │ └── feature_phone.yml │ ├── client │ │ ├── mobile_app.yml │ │ ├── library.yml │ │ ├── pim.yml │ │ ├── mediaplayer.yml │ │ └── feed_reader.yml │ └── parser │ │ └── vendorfragments.yml ├── spec_helper.rb ├── device_detector │ ├── os_fixtures_spec.rb │ ├── bot_fixtures_spec.rb │ ├── client_fixtures_spec.rb │ ├── device_fixtures_spec.rb │ ├── model_extractor_spec.rb │ ├── version_extractor_spec.rb │ ├── detector_fixtures_spec.rb │ ├── memory_cache_spec.rb │ ├── concrete_user_agent_spec.rb │ └── device_spec.rb └── device_detector_spec.rb ├── Gemfile ├── .travis.yml ├── regexes ├── device │ ├── car_browsers.yml │ ├── cameras.yml │ ├── consoles.yml │ ├── portable_media_player.yml │ └── televisions.yml ├── client │ ├── browser_engine.yml │ ├── libraries.yml │ ├── pim.yml │ ├── mobile_apps.yml │ ├── mediaplayers.yml │ ├── feed_readers.yml │ └── browsers.yml ├── vendorfragments.yml └── oss.yml ├── device_detector.gemspec ├── CHANGELOG.md ├── Rakefile ├── LICENSE.txt └── README.md /lib/device_detector/version.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | VERSION = '0.9.0' 3 | end 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | -------------------------------------------------------------------------------- /spec/fixtures/device/car_browser.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Mozilla/5.0 (X11; u; Linux; C) AppleWebKit /533.3 (Khtml, like Gheko) QtCarBrowser Safari/533.3 3 | device: 4 | type: 6 5 | brand: TA 6 | model: Model S -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in device_detector.gemspec 4 | gemspec 5 | 6 | if RUBY_VERSION >= "2.0" && defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" 7 | gem 'byebug' 8 | end 9 | -------------------------------------------------------------------------------- /lib/device_detector/bot.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class Bot < Parser 3 | 4 | def bot? 5 | regex_meta.any? 6 | end 7 | 8 | private 9 | 10 | def filenames 11 | ['bots.yml'] 12 | end 13 | 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/device_detector/version_extractor.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class VersionExtractor < MetadataExtractor 3 | 4 | private 5 | 6 | def metadata_string 7 | String(regex_meta[:version]) 8 | end 9 | 10 | end 11 | end 12 | 13 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'minitest/spec' 3 | 4 | $:.unshift(File.expand_path('../../lib', __FILE__)) 5 | require 'device_detector' 6 | begin 7 | require "byebug" 8 | rescue LoadError 9 | end unless RUBY_VERSION < "2.0.0" || RUBY_ENGINE != "ruby" 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | sudo: false 3 | rvm: 4 | - 1.9.3 5 | - 2.0.0-p648 6 | - 2.1.10 7 | - 2.2.5 8 | - 2.3.1 9 | - ruby-head 10 | - rbx-2 11 | before_install: 12 | - gem update --system 13 | - gem --version 14 | - gem update bundler 15 | - bundler --version 16 | cache: bundler 17 | script: 18 | bundle exec rake test 19 | -------------------------------------------------------------------------------- /regexes/device/car_browsers.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | # Tesla Model S 9 | Tesla: 10 | regex: 'QtCarBrowser' 11 | device: 'car browser' 12 | model: 'Model S' 13 | -------------------------------------------------------------------------------- /lib/device_detector/name_extractor.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class NameExtractor < MetadataExtractor 3 | 4 | def call 5 | if /\$[0-9]/ =~ metadata_string 6 | extract_metadata 7 | else 8 | metadata_string 9 | end 10 | end 11 | 12 | private 13 | 14 | def metadata_string 15 | regex_meta[:name] 16 | end 17 | 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/device_detector/client.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class Client < Parser 3 | 4 | def known? 5 | regex_meta.any? 6 | end 7 | 8 | private 9 | 10 | def filenames 11 | [ 12 | 'client/feed_readers.yml', 13 | 'client/mobile_apps.yml', 14 | 'client/mediaplayers.yml', 15 | 'client/pim.yml', 16 | 'client/browsers.yml', 17 | 'client/libraries.yml', 18 | ] 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/fixtures/detector/car_browser.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | user_agent: Mozilla/5.0 (X11; u; Linux; C) AppleWebKit /533.3 (Khtml, like Gheko) QtCarBrowser Safari/533.3 4 | os: 5 | name: GNU/Linux 6 | short_name: LIN 7 | version: 8 | platform: 9 | client: 10 | type: browser 11 | name: Safari 12 | short_name: SF 13 | version: 14 | engine: WebKit 15 | device: 16 | type: car browser 17 | brand: TA 18 | model: Model S 19 | os_family: GNU/Linux 20 | browser_family: Safari 21 | -------------------------------------------------------------------------------- /lib/device_detector/model_extractor.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class ModelExtractor < MetadataExtractor 3 | 4 | def call 5 | s = super.to_s.gsub('_',' ').strip 6 | s = s.gsub(/ TD$/i, '') 7 | 8 | return nil if s == 'Build' 9 | 10 | s.empty? ? nil : s 11 | end 12 | 13 | private 14 | 15 | def metadata_string 16 | String(regex_meta[:model]) 17 | end 18 | 19 | def regex 20 | @regex ||= regex_meta[:regex_model] || regex_meta[:regex] 21 | end 22 | 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /regexes/client/browser_engine.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | - regex: 'NetFront' 9 | name: 'NetFront' 10 | 11 | - regex: 'Edge' 12 | name: 'Edge' 13 | 14 | - regex: 'Trident' 15 | name: 'Trident' 16 | 17 | - regex: 'Blink' 18 | name: 'Blink' 19 | 20 | - regex: '(?:Apple)?WebKit' 21 | name: 'WebKit' 22 | 23 | - regex: 'Presto' 24 | name: 'Presto' 25 | 26 | - regex: '(?= 1.9.3' 22 | 23 | spec.add_development_dependency 'minitest' 24 | spec.add_development_dependency 'rake' 25 | spec.add_development_dependency 'pry', '>= 0.10' 26 | end 27 | -------------------------------------------------------------------------------- /spec/device_detector/device_fixtures_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../spec_helper' 2 | 3 | describe DeviceDetector::Device do 4 | 5 | fixture_dir = File.expand_path('../../fixtures/devices', __FILE__) 6 | fixture_files = Dir["#{fixture_dir}/*.yml"] 7 | fixture_files.each do |fixture_file| 8 | 9 | describe File.basename(fixture_file) do 10 | 11 | fixtures = YAML.load_file(fixture_file) 12 | fixtures.each do |f| 13 | 14 | user_agent = f["user_agent"] 15 | device = DeviceDetector::Device.new(user_agent) 16 | 17 | describe user_agent do 18 | 19 | it "should be known" do 20 | assert device.known?, "isn't known as a device" 21 | end 22 | 23 | it "should have the expected model" do 24 | assert_equal f["device"]["model"], device.name, "failed model detection" 25 | end 26 | 27 | it "should have the expected type" do 28 | expected_device_type = DeviceDetector::Device::DEVICE_NAMES[f["device"]["type"]] 29 | assert_equal expected_device_type, device.type, "failed device name detection" 30 | end 31 | 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /regexes/vendorfragments.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | Dell: 9 | - 'MDDR(JS)?' 10 | - 'MDDC(JS)?' 11 | - 'MDDS(JS)?' 12 | 13 | Acer: 14 | - 'MAAR(JS)?' 15 | 16 | Sony: 17 | - 'MASE(JS)?' 18 | - 'MASP(JS)?' 19 | - 'MASA(JS)?' 20 | 21 | Asus: 22 | - 'MAAU' 23 | - 'NP0[6789]' 24 | - 'ASJB' 25 | - 'ASU2(JS)?' 26 | 27 | Samsung: 28 | - 'MASM(JS)?' 29 | - 'SMJB' 30 | 31 | Lenovo: 32 | - 'MALC(JS)?' 33 | - 'MALE(JS)?' 34 | - 'MALN(JS)?' 35 | - 'LCJB' 36 | - 'LEN2' 37 | 38 | Toshiba: 39 | - 'MATM(JS)?' 40 | - 'MATB(JS)?' 41 | - 'MATP(JS)?' 42 | - 'TNJB' 43 | - 'TAJB' 44 | 45 | Medion: 46 | - 'MAMD' 47 | 48 | MSI: 49 | - 'MAMI(JS)?' 50 | - 'MAM3' 51 | 52 | Gateway: 53 | - 'MAGW(JS)?' 54 | 55 | Fujitsu: 56 | - 'MAFS(JS)?' 57 | - 'FSJB' 58 | 59 | Compaq: 60 | - 'CPDTDF' 61 | - 'CPNTDF(JS?)' 62 | - 'CMNTDF(JS)?' 63 | - 'CMDTDF(JS)?' 64 | 65 | HP: 66 | - 'HPCMHP' 67 | - 'HPNTDF(JS)?' 68 | - 'HPDTDF(JS)?' 69 | 70 | Hyrican: 71 | - 'MANM(JS)?' 72 | -------------------------------------------------------------------------------- /lib/device_detector/memory_cache.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class MemoryCache 3 | 4 | DEFAULT_MAX_KEYS = 5000 5 | 6 | attr_reader :data, :max_keys, :lock 7 | private :lock 8 | 9 | def initialize(config) 10 | @data = {} 11 | @max_keys = config[:max_cache_keys] || DEFAULT_MAX_KEYS 12 | @lock = Mutex.new 13 | end 14 | 15 | def set(key, value) 16 | lock.synchronize do 17 | purge_cache 18 | data[String(key)] = value 19 | end 20 | end 21 | 22 | def get(key) 23 | data[String(key)] 24 | end 25 | 26 | def key?(string_key) 27 | data.key?(string_key) 28 | end 29 | 30 | def get_or_set(key, value = nil) 31 | string_key = String(key) 32 | 33 | if key?(string_key) 34 | get(string_key) 35 | else 36 | value = yield if block_given? 37 | set(string_key, value) 38 | end 39 | end 40 | 41 | private 42 | 43 | def purge_cache 44 | key_size = data.size 45 | 46 | if key_size >= max_keys 47 | # always remove about 1/3 of keys to reduce garbage collecting 48 | amount_of_keys = key_size / 3 49 | 50 | data.keys.first(amount_of_keys).each { |key| data.delete(key) } 51 | end 52 | end 53 | 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [0.9.0] 4 | - Preparing for the 1.0.0 release. This version (with minor bumps) will be promoted to 1.0.0 once the release has been proven stable 5 | - Updated regex files from upstream 6 | - Updated test fixtures from upstream 7 | 8 | ## [0.8.2] 9 | - Added device brand support. Thanks to [dnswus](https://github.com/dnswus) 10 | 11 | ## [0.8.1] 12 | - Added Instacast detection rules 13 | - Updated test fixtures 14 | 15 | ## [0.8.0] 16 | - Added a better and more robust device detection. Thanks to [skaes](https://github.com/skaes) 17 | - Added test fixture from the piwik project 18 | 19 | ## [0.7.0] 20 | - [Issue #8](https://github.com/podigee/device_detector/issues/8) Fixed Mac OS X full version format. Thanks to [aaronchi](https://github.com/aaronchi) for reporting 21 | 22 | ## [0.6.0] 23 | 24 | - [Issue #7](https://github.com/podigee/device_detector/issues/7) Fixed missing name extraction from regexp. Thanks to [janxious](https://github.com/janxious) for reporting 25 | - Optimized performance of name and version extraction, by using the built-in memory cache 26 | - Move specs from RSpec to the more lightweight Minitest 27 | 28 | ## [0.5.1] 29 | 30 | - Added the minimum required Ruby version (>= 1.9.3) 31 | 32 | ## [0.5.0] 33 | 34 | - Added rake task for automatic generation of supported and detectable clients and devices 35 | - Updated detection rules 36 | - Fixed device type detection, when type is specified on top level of a nested regex 37 | 38 | -------------------------------------------------------------------------------- /regexes/client/mobile_apps.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | # AndroidDownloadManager 9 | - regex: 'AndroidDownloadManager(?:[ /]([\d\.]+))?' 10 | name: 'AndroidDownloadManager' 11 | version: '$1' 12 | 13 | # Facebook 14 | - regex: '(?:FBAV|com.facebook.katana)(?:[ /]([\d\.]+))?' 15 | name: 'Facebook' 16 | version: '$1' 17 | 18 | # FeedR 19 | - regex: 'FeedR(?:/([\d\.]+))?' 20 | name: 'FeedR' 21 | version: '$1' 22 | 23 | # Google Play Kiosk 24 | - regex: 'com.google.android.apps.magazines' 25 | name: 'Google Play Newsstand' 26 | version: '' 27 | 28 | # Google Plus 29 | - regex: 'com.google.GooglePlus' 30 | name: 'Google Plus' 31 | version: '' 32 | 33 | # WeChat 34 | - regex: 'MicroMessenger/([^ ]+)' 35 | name: 'WeChat' 36 | version: '$1' 37 | 38 | # Sina Weibo 39 | - regex: '.*__weibo__([0-9\.]+)__' 40 | name: 'Sina Weibo' 41 | version: '$1' 42 | 43 | # Pinterest 44 | - regex: 'Pinterest(?:/([\d\.]+))?' 45 | name: 'Pinterest' 46 | version: '$1' 47 | 48 | # YouTube 49 | - regex: 'com.google.android.youtube(?:/([\d\.]+))?' 50 | name: 'YouTube' 51 | version: '$1' 52 | 53 | # AFNetworking generic 54 | - regex: '([^/]+)/(\d+(?:\.\d+)+) \((?:iPhone|iPad); iOS [0-9\.]+; Scale/[0-9\.]+\)' 55 | name: '$1' 56 | version: '$2' 57 | 58 | # WhatsApp 59 | - regex: 'WhatsApp(?:[ /]([\d\.]+))?' 60 | name: 'WhatsApp' 61 | version: '$1' 62 | 63 | # Line 64 | - regex: 'Line(?:[ /]([\d\.]+))' 65 | name: 'Line' 66 | version: '$1' -------------------------------------------------------------------------------- /spec/fixtures/detector/smart_display.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | user_agent: Mozilla/5.0 (Linux; U; Android 4.0.4; fr-be; DA220HQL Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 4 | os: 5 | name: Android 6 | short_name: AND 7 | version: "4.0.4" 8 | platform: 9 | client: 10 | type: browser 11 | name: Android Browser 12 | short_name: AN 13 | version: 14 | engine: WebKit 15 | device: 16 | type: smart display 17 | brand: AC 18 | model: DA220HQL 19 | os_family: Android 20 | browser_family: Android Browser 21 | - 22 | user_agent: Mozilla/5.0 (Linux; Android 4.2.1; DA241HL Build/JOP40D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Safari/537.36 23 | os: 24 | name: Android 25 | short_name: AND 26 | version: "4.2.1" 27 | platform: 28 | client: 29 | type: browser 30 | name: Chrome 31 | short_name: CH 32 | version: "34.0.1847.114" 33 | engine: Blink 34 | device: 35 | type: smart display 36 | brand: AC 37 | model: DA241HL 38 | os_family: Android 39 | browser_family: Chrome 40 | - 41 | user_agent: Mozilla/5.0 (Linux; U; Android 4.0.4; de-de; VSD220 Build/IMM76D.UI23ED12_VSC) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 42 | os: 43 | name: Android 44 | short_name: AND 45 | version: "4.0.4" 46 | platform: 47 | client: 48 | type: browser 49 | name: Android Browser 50 | short_name: AN 51 | version: 52 | engine: WebKit 53 | device: 54 | type: smart display 55 | brand: VS 56 | model: VSD220 57 | os_family: Android 58 | browser_family: Android Browser 59 | -------------------------------------------------------------------------------- /regexes/device/portable_media_player.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | Apple: 9 | regex: '(?:Apple-)?iPod' 10 | device: 'portable media player' 11 | models: 12 | - regex: '(?:Apple-)?iPod1[C,]1' 13 | model: 'iPod Touch 1G' 14 | - regex: '(?:Apple-)?iPod2[C,]1' 15 | model: 'iPod Touch 2G' 16 | - regex: '(?:Apple-)?iPod3[C,]1' 17 | model: 'iPod Touch 3' 18 | - regex: '(?:Apple-)?iPod4[C,]1' 19 | model: 'iPod Touch 4' 20 | - regex: '(?:Apple-)?iPod5[C,]1' 21 | model: 'iPod Touch 5' 22 | - regex: '(?:Apple-)?iPod1[C,]1' 23 | model: 'iPod Touch' 24 | - regex: '(?:Apple-)?iPod1[C,]1' 25 | model: 'iPod Touch' 26 | - regex: '(?:Apple-)?iPod' 27 | model: 'iPod Touch' 28 | 29 | Cowon: 30 | regex: 'COWON ([^;/]+) Build' 31 | device: 'portable media player' 32 | model: '$1' 33 | 34 | Microsoft: 35 | regex: 'Microsoft ZuneHD' 36 | device: 'portable media player' 37 | model: 'Zune HD' 38 | 39 | Panasonic: 40 | device: 'portable media player' 41 | regex: '(SV-MV100)' 42 | model: '$1' 43 | 44 | Samsung: 45 | regex: 'YP-(G[SIPB]?1|G[57]0|GB70D)' 46 | device: 'portable media player' 47 | models: 48 | - regex: 'YP-G[B]?1' 49 | model: 'Galaxy Player 4.0' 50 | - regex: 'YP-G70' 51 | model: 'Galaxy Player 5.0' 52 | - regex: 'YP-GS1' 53 | model: 'Galaxy Player 3.6' 54 | - regex: 'YP-GI1' 55 | model: 'Galaxy Player 4.2' 56 | - regex: 'YP-GP1' 57 | model: 'Galaxy Player 5.8 ' 58 | - regex: 'YP-G50' 59 | model: 'Galaxy Player 50' 60 | - regex: 'YP-GB70D' 61 | model: 'Galaxy Player 70 Plus' 62 | -------------------------------------------------------------------------------- /regexes/client/mediaplayers.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | - regex: 'Banshee(?:[ /]([\d\.]+))?' 9 | name: 'Banshee' 10 | version: '$1' 11 | 12 | - regex: 'Boxee(?:[ /]([\d\.]+))?' 13 | name: 'Boxee' 14 | version: '$1' 15 | 16 | - regex: 'Clementine(?:[ /]([\d\.]+))?' 17 | name: 'Clementine' 18 | version: '$1' 19 | 20 | - regex: 'iTunes(?:/([\d\.]+))?' 21 | name: 'iTunes' 22 | version: '$1' 23 | 24 | - regex: 'FlyCast(?:/([\d\.]+))?' 25 | name: 'FlyCast' 26 | version: '$1' 27 | 28 | - regex: 'MediaMonkey(?:[ /](\d+[\.\d]+))?' 29 | name: 'MediaMonkey' 30 | version: '$1' 31 | 32 | - regex: 'Miro(?:/(\d+[\.\d]+))?' 33 | name: 'Miro' 34 | version: '$1' 35 | 36 | - regex: 'NexPlayer(?:/(\d+[\.\d]+))?' 37 | name: 'NexPlayer' 38 | version: '$1' 39 | 40 | - regex: 'Nightingale(?:/([\d\.]+))?' 41 | name: 'Nightingale' 42 | version: '$1' 43 | 44 | - regex: 'QuickTime(?:(?:(?:.+qtver=)|(?:(?: E-)?[\./]))([\d\.]+))?' 45 | name: 'QuickTime' 46 | version: '$1' 47 | 48 | - regex: 'Songbird(?:/([\d\.]+))?' 49 | name: 'Songbird' 50 | version: '$1' 51 | 52 | - regex: 'SubStream(?:/([\d\.]+))?' 53 | name: 'SubStream' 54 | version: '$1' 55 | 56 | - regex: '(?:Lib)?VLC(?:/([\d\.]+))?' 57 | name: 'VLC' 58 | version: '$1' 59 | 60 | - regex: 'Winamp(?:MPEG)?(?:/(\d+[\.\d]+))?' 61 | name: 'Winamp' 62 | version: '$1' 63 | 64 | - regex: '(?:Windows-Media-Player|NSPlayer)(?:/(\d+[\.\d]+))?' 65 | name: 'Windows Media Player' 66 | version: '$1' 67 | 68 | - regex: 'XBMC(?:/([\d\.]+))?' 69 | name: 'XBMC' 70 | version: '$1' 71 | 72 | - regex: 'Kodi(?:/([\d\.]+))?' 73 | name: 'Kodi' 74 | version: '$1' 75 | 76 | - regex: 'stagefright(?:/([\d\.]+))?' 77 | name: 'Stagefright' 78 | version: '$1' 79 | 80 | - regex: 'Instacast(?:/([\d\.]+))? CFNetwork/([\d\.]+)' 81 | name: 'Instacast' 82 | version: '$1' -------------------------------------------------------------------------------- /spec/fixtures/client/library.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Wget/1.10+devel 3 | client: 4 | type: library 5 | name: Wget 6 | version: "1.10" 7 | - 8 | user_agent: Wget/1.11.4 Red Hat modified 9 | client: 10 | type: library 11 | name: Wget 12 | version: "1.11.4" 13 | - 14 | user_agent: Wget/ (linux-gnu) 15 | client: 16 | type: library 17 | name: Wget 18 | version: 19 | - 20 | user_agent: curl/7.21.0 (i386-redhat-linux-gnu) libcurl/7.21.0 NSS/3.12.10.0 zlib/1.2.5 libidn/1.18 libssh2/1.2.4 21 | client: 22 | type: library 23 | name: curl 24 | version: "7.21.0" 25 | - 26 | user_agent: PycURL/7.19.3.1 libcurl/7.26.0 GnuTLS/2.12.20 zlib/1.2.7 libidn/1.25 libssh2/1.4.2 librtmp/2.3 27 | client: 28 | type: library 29 | name: curl 30 | version: "7.26.0" 31 | - 32 | user_agent: python-requests/1.2.0 CPython/2.7.3 Linux/3.8.0-33-generic 33 | client: 34 | type: library 35 | name: Python Requests 36 | version: "1.2.0" 37 | - 38 | user_agent: python-requests/1.2.0 CPython/2.7.5 Windows/7 39 | client: 40 | type: library 41 | name: Python Requests 42 | version: "1.2.0" 43 | - 44 | user_agent: Python-urllib/2.6 45 | client: 46 | type: library 47 | name: Python urllib 48 | version: "2.6" 49 | - 50 | user_agent: Mozilla/5.0 (Python-urllib2) 51 | client: 52 | type: library 53 | name: Python urllib 54 | version: 55 | - 56 | user_agent: Java/1.7.0_51 57 | client: 58 | type: library 59 | name: Java 60 | version: "1.7.0" 61 | - 62 | user_agent: Java1.1.4 63 | client: 64 | type: library 65 | name: Java 66 | version: "1.1.4" 67 | - 68 | user_agent: libwww-perl/5.69 69 | client: 70 | type: library 71 | name: Perl 72 | version: "5.69" 73 | - 74 | user_agent: perlclient/1.0 75 | client: 76 | type: library 77 | name: Perl 78 | version: "1.0" 79 | - 80 | user_agent: Guzzle/3.9.3 curl/7.38.0 PHP/5.6.14-0+deb8u1 81 | client: 82 | type: library 83 | name: Guzzle (PHP HTTP Client) 84 | version: "3.9.3" -------------------------------------------------------------------------------- /spec/device_detector/model_extractor_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../spec_helper' 2 | 3 | describe DeviceDetector::ModelExtractor do 4 | 5 | subject { DeviceDetector::ModelExtractor.new(user_agent, regex_meta) } 6 | 7 | alias :extractor :subject 8 | 9 | describe '#call' do 10 | 11 | describe 'when matching against dynamic model' do 12 | 13 | let(:regex_meta) do 14 | { 15 | :regex => '(?:Apple-)?iPhone ?(3GS?|4S?|5[CS]?|6(:? Plus)?)?', 16 | :model => 'iPhone $1', 17 | :device => 'smartphone' 18 | } 19 | end 20 | 21 | describe 'when no dynamic match is found' do 22 | let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B466 Safari/600.1.4' } 23 | let(:device_name) { 'iPhone' } 24 | 25 | it 'returns the textual portion without trailing whitespace' do 26 | extractor.call.must_equal device_name 27 | end 28 | 29 | end 30 | 31 | describe 'when a dynamic match is found' do 32 | let(:user_agent) { 'Mozilla/5.0 (iPhone 5S; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B466 Safari/600.1.4' } 33 | let(:device_name) { 'iPhone 5S' } 34 | 35 | it 'returns the full device name' do 36 | extractor.call.must_equal device_name 37 | end 38 | 39 | end 40 | 41 | end 42 | 43 | describe 'when matching against static model' do 44 | 45 | let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12A365 Weibo (iPhone7,2)' } 46 | let(:device_name) { 'iPhone 6' } 47 | let(:regex_meta) do 48 | { 49 | :regex => '(?:Apple-)?iPhone7[C,]2', 50 | :model => 'iPhone 6', 51 | :device => 'smartphone' 52 | } 53 | end 54 | 55 | it 'returns the model name' do 56 | extractor.call.must_equal device_name 57 | end 58 | 59 | end 60 | 61 | end 62 | 63 | end 64 | -------------------------------------------------------------------------------- /spec/device_detector/version_extractor_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../spec_helper' 2 | 3 | describe DeviceDetector::VersionExtractor do 4 | 5 | subject { DeviceDetector::VersionExtractor.new(user_agent, regex_meta) } 6 | 7 | alias :extractor :subject 8 | 9 | describe '#call' do 10 | 11 | describe 'extractor without version' do 12 | 13 | let(:user_agent) { 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; Avant Browser; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)' } 14 | 15 | let(:regex_meta) do 16 | { 17 | :regex => 'Avant Browser', 18 | :name => 'Avant Browser', 19 | :version => '' 20 | } 21 | end 22 | 23 | it 'returns nil' do 24 | extractor.call.must_equal '' 25 | end 26 | 27 | end 28 | 29 | describe 'regex with dynamic matching' do 30 | 31 | let(:user_agent) { 'Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.8.1b2) Gecko/20060821 BonEcho/2.0b2 (Debian-1.99+2.0b2+dfsg-1)' } 32 | let(:version) { 'BonEcho (2.0)' } 33 | let(:regex_meta) do 34 | { 35 | :regex => '(BonEcho|GranParadiso|Lorentz|Minefield|Namoroka|Shiretoko)/(\d+[\.\d]+)', 36 | :name => 'Firefox', 37 | :version => '$1 ($2)' 38 | } 39 | end 40 | 41 | it 'returns the correct version' do 42 | extractor.call.must_equal version 43 | end 44 | 45 | it 'removes trailing white spaces' do 46 | regex_meta[:version] = regex_meta[:version] + ' ' 47 | extractor.call.must_equal version 48 | end 49 | 50 | end 51 | 52 | describe 'extractor with fixed version' do 53 | 54 | let(:user_agent) { 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)' } 55 | let(:regex_meta) do 56 | { 57 | :regex => 'MSIE.*Trident/4.0', 58 | :version => '8.0' 59 | } 60 | end 61 | 62 | it 'returns the correct version' do 63 | extractor.call.must_equal '8.0' 64 | end 65 | 66 | end 67 | 68 | describe 'unknown user agent' do 69 | 70 | let(:user_agent) { 'garbage' } 71 | let(:regex_meta) { {} } 72 | 73 | it 'returns nil' do 74 | extractor.call.must_be_nil 75 | end 76 | 77 | end 78 | end 79 | end 80 | 81 | -------------------------------------------------------------------------------- /lib/device_detector/parser.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class Parser < Struct.new(:user_agent) 3 | 4 | ROOT = File.expand_path('../../..', __FILE__) 5 | 6 | def name 7 | from_cache(['name', self.class.name, user_agent]) do 8 | NameExtractor.new(user_agent, regex_meta).call 9 | end 10 | end 11 | 12 | def full_version 13 | from_cache(['full_version', self.class.name, user_agent]) do 14 | VersionExtractor.new(user_agent, regex_meta).call 15 | end 16 | end 17 | 18 | private 19 | 20 | def regex_meta 21 | @regex_meta ||= matching_regex || {} 22 | end 23 | 24 | def matching_regex 25 | from_cache([self.class.name, user_agent]) do 26 | regexes.find { |r| user_agent =~ r[:regex] } 27 | end 28 | end 29 | 30 | def regexes 31 | @regexes ||= regexes_for(filepaths) 32 | end 33 | 34 | def filenames 35 | fail NotImplementedError 36 | end 37 | 38 | def filepaths 39 | filenames.map do |filename| 40 | [ filename.to_sym, File.join(ROOT, 'regexes', filename) ] 41 | end 42 | end 43 | 44 | def regexes_for(file_paths) 45 | from_cache(['regexes', self.class]) do 46 | load_regexes(file_paths).flat_map { |path, regex| parse_regexes(path, regex) } 47 | end 48 | end 49 | 50 | def load_regexes(file_paths) 51 | file_paths.map { |path, full_path| [path, symbolize_keys!(YAML.load_file(full_path))] } 52 | end 53 | 54 | def symbolize_keys!(object) 55 | case object 56 | when Array 57 | object.map!{ |v| symbolize_keys!(v) } 58 | when Hash 59 | object.keys.each{ |k| object[k.to_sym] = symbolize_keys!(object.delete(k)) if k.is_a?(String) } 60 | end 61 | object 62 | end 63 | 64 | def parse_regexes(path, raw_regexes) 65 | raw_regexes.map do |meta| 66 | fail "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String 67 | meta[:regex] = build_regex(meta[:regex]) 68 | meta[:path] = path 69 | meta 70 | end 71 | end 72 | 73 | def build_regex(src) 74 | Regexp.new('(?:^|[^A-Z0-9\-_]|[^A-Z0-9\-]_|sprd-)(?:' + src + ')', Regexp::IGNORECASE) 75 | end 76 | 77 | def from_cache(key) 78 | DeviceDetector.cache.get_or_set(key) { yield } 79 | end 80 | 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/fixtures/device/console.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Mozilla/5.0 (Linux; Android 4.1.1; ARCHOS GAMEPAD Build/JRO03H) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 3 | device: 4 | type: 4 5 | brand: AR 6 | model: Gamepad 7 | - 8 | user_agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox) 9 | device: 10 | type: 4 11 | brand: MS 12 | model: Xbox 360 13 | - 14 | user_agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Xbox; Xbox One) 15 | device: 16 | type: 4 17 | brand: MS 18 | model: Xbox One 19 | - 20 | user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586 21 | device: 22 | type: 4 23 | brand: MS 24 | model: Xbox One 25 | - 26 | user_agent: Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7498.EU 27 | device: 28 | type: 4 29 | brand: NI 30 | model: 3DS 31 | - 32 | user_agent: Bunjalloo/0.7.6(Nintendo DS;U;en) 33 | device: 34 | type: 4 35 | brand: NI 36 | model: DS 37 | - 38 | user_agent: Opera/9.30 (Nintendo Wii; U; ; 3642; en) 39 | device: 40 | type: 4 41 | brand: NI 42 | model: Wii 43 | - 44 | user_agent: Mozilla/5.0 (Nintendo WiiU) AppleWebKit/534.52 (KHTML, like Gecko) NX/2.1.0.8.21 NintendoBrowser/1.0.0.7494.US 45 | device: 46 | type: 4 47 | brand: NI 48 | model: WiiU 49 | - 50 | user_agent: Mozilla/5.0 (Linux; U; Android OUYA 4.1.2; en-us; OUYA Build/JZO54L-OUYA) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 51 | device: 52 | type: 4 53 | brand: OU 54 | model: OUYA 55 | - 56 | user_agent: Mozilla/5.0 (PLAYSTATION 3 4.46) AppleWebKit/531.22.8 (KHTML, like Gecko) 57 | device: 58 | type: 4 59 | brand: SO 60 | model: PlayStation 3 61 | - 62 | user_agent: Mozilla/5.0 (PlayStation 4 1.52) AppleWebKit/536.26 (KHTML, like Gecko) 63 | device: 64 | type: 4 65 | brand: SO 66 | model: PlayStation 4 67 | - 68 | user_agent: Mozilla/4.0 (PlayStation Portable); 2.00) 69 | device: 70 | type: 4 71 | brand: SO 72 | model: PlayStation Portable 73 | - 74 | user_agent: Mozilla/5.0 (PlayStation Vita 3.01) AppleWebKit/536.26 (KHTML, like Gecko) Silk/3.2 75 | device: 76 | type: 4 77 | brand: SO 78 | model: PlayStation Vita -------------------------------------------------------------------------------- /spec/device_detector/detector_fixtures_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../spec_helper' 2 | 3 | describe DeviceDetector do 4 | 5 | fixture_dir = File.expand_path('../../fixtures/detector', __FILE__) 6 | fixture_files = Dir["#{fixture_dir}/*.yml"] 7 | fixture_files.each do |fixture_file| 8 | 9 | describe File.basename(fixture_file) do 10 | 11 | fixtures = nil 12 | begin 13 | fixtures = YAML.load(File.read(fixture_file)) 14 | rescue Psych::SyntaxError => e 15 | fail "Failed to parse #{fixture_file}, reason: #{e}" 16 | end 17 | 18 | fixtures.each do |f| 19 | 20 | user_agent = f["user_agent"] 21 | detector = DeviceDetector.new(user_agent) 22 | os = detector.send(:os) 23 | 24 | describe user_agent do 25 | it "should be detected" do 26 | if detector.bot? 27 | assert_equal f["bot"]["name"], detector.bot_name, "failed bot name detection" 28 | else 29 | if f["client"] 30 | assert_equal f["client"]["name"], detector.name, "failed client name detection" 31 | end 32 | if f["os_family"] != "Unknown" 33 | assert_equal f["os_family"], os.family, "failed os family detection" 34 | assert_equal f["os"]["name"], os.name, "failed os name detection" 35 | assert_equal f["os"]["short_name"], os.short_name, "failed os short name detection" 36 | assert_equal f["os"]["version"], os.full_version, "failed os version detection" 37 | end 38 | if f["device"] 39 | expected_type = f["device"]["type"] 40 | actual_type = detector.device_type 41 | if expected_type != actual_type 42 | # puts "\n", f.inspect, expected_type, actual_type, detector.device_name, regex_meta.inspect 43 | # debugger 44 | # detector.device_type 45 | end 46 | assert_equal expected_type, actual_type, "failed device type detection" 47 | model = f["device"]["model"] 48 | model = model.to_s unless model.nil? 49 | assert_equal model, detector.device_name, "failed device name detection" 50 | end 51 | end 52 | end 53 | end 54 | end 55 | 56 | end 57 | 58 | end 59 | 60 | end 61 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rake/testtask' 3 | 4 | $:.unshift 'lib' 5 | require 'device_detector' 6 | 7 | Rake::TestTask.new do |t| 8 | t.pattern = 'spec/**/*_spec.rb' 9 | t.libs.push 'spec' 10 | end 11 | 12 | task default: :test 13 | 14 | task :detectable_names do 15 | bot_names = DeviceDetector::Bot.new.send(:regexes).map { |r| r[:name] }.uniq.sort_by { |n| n.downcase } 16 | bot_names.delete('$1') 17 | client_names = DeviceDetector::Client.new.send(:regexes).map { |r| r[:name] }.uniq.sort_by { |n| n.downcase } 18 | client_names.delete('$1') 19 | device = DeviceDetector::Device.new 20 | device_paths = device.send(:filepaths) 21 | device_regexes = device.send(:load_regexes, device_paths) 22 | device_names = device_regexes.flat_map { |dn| dn[1].keys }.uniq.sort_by { |n| n.downcase } 23 | 24 | today = Date.today.strftime 25 | 26 | puts '## Detectable clients, bots and devices' 27 | puts 28 | puts "Updated on #{today}" 29 | puts 30 | puts '### Bots' 31 | puts 32 | puts bot_names.join(', ') 33 | puts 34 | puts '### Clients' 35 | puts 36 | puts client_names.join(', ') 37 | puts 38 | puts '### Devices' 39 | puts 40 | puts device_names.join(', ') 41 | puts 42 | end 43 | 44 | PIWIK_REPO_URL = 'https://github.com/piwik/device-detector.git'.freeze 45 | PIWIK_CHECKOUT_LOCATION = '/tmp/piwik_device_detector'.freeze 46 | 47 | def get_latest_piwik_checkout 48 | if File.exist?(PIWIK_CHECKOUT_LOCATION) 49 | system "cd #{PIWIK_CHECKOUT_LOCATION}; git reset --hard HEAD; git pull origin master" 50 | else 51 | system "git clone --depth 1 #{PIWIK_REPO_URL} #{PIWIK_CHECKOUT_LOCATION}" 52 | end 53 | end 54 | 55 | desc 'update regex database from piwik project' 56 | task :update_regexes do 57 | top = File.expand_path('..', __FILE__) 58 | get_latest_piwik_checkout 59 | system "cp -R #{PIWIK_CHECKOUT_LOCATION}/regexes/* #{top}/regexes" 60 | end 61 | 62 | desc 'update fixtures from piwik project' 63 | task :update_fixtures do 64 | top = File.expand_path('..', __FILE__) 65 | get_latest_piwik_checkout 66 | 67 | fixture_mappings = [ 68 | {target_path: "#{top}/spec/fixtures/detector", source_path: 'Tests/fixtures/*.yml'}, 69 | {target_path: "#{top}/spec/fixtures/client", source_path: 'Tests/Parser/Client/fixtures/*.yml'}, 70 | {target_path: "#{top}/spec/fixtures/parser", source_path: 'Tests/Parser/fixtures/*.yml'}, 71 | {target_path: "#{top}/spec/fixtures/device", source_path: 'Tests/Parser/Devices/fixtures/*.yml'}, 72 | ] 73 | 74 | fixture_mappings.each do |mapping| 75 | source_path = mapping.fetch(:source_path) 76 | target_path = mapping.fetch(:target_path) 77 | system "cp -R #{PIWIK_CHECKOUT_LOCATION}/#{source_path} #{target_path}" 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /spec/device_detector/memory_cache_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../spec_helper' 2 | 3 | describe DeviceDetector::MemoryCache do 4 | 5 | let(:subject) { DeviceDetector::MemoryCache.new(config) } 6 | 7 | let(:config) { {} } 8 | 9 | describe '#set' do 10 | 11 | describe 'string key' do 12 | 13 | let(:key) { 'string' } 14 | 15 | it 'sets the value under the key' do 16 | subject.set(key, 'value') 17 | 18 | subject.data[key].must_equal 'value' 19 | end 20 | 21 | end 22 | 23 | describe 'array key' do 24 | 25 | let(:key) { ['string1', 'string2'] } 26 | 27 | it 'sets the value under the key' do 28 | subject.set(key, 'value') 29 | 30 | subject.data[String(key)].must_equal 'value' 31 | end 32 | 33 | end 34 | 35 | end 36 | 37 | describe '#get' do 38 | 39 | describe 'string key' do 40 | 41 | let(:key) { 'string' } 42 | 43 | it 'gets the value for the key' do 44 | subject.data[key] = 'value' 45 | 46 | subject.get(key).must_equal 'value' 47 | end 48 | 49 | end 50 | 51 | describe 'array key' do 52 | 53 | let(:key) { ['string1', 'string2'] } 54 | 55 | it 'gets the value for the key' do 56 | subject.data[String(key)] = 'value' 57 | 58 | subject.get(key).must_equal 'value' 59 | end 60 | 61 | end 62 | 63 | end 64 | 65 | describe '#get_or_set' do 66 | 67 | let(:key) { 'string' } 68 | 69 | describe 'value already present' do 70 | 71 | it 'gets the value for the key from cache' do 72 | subject.data[key] = 'value' 73 | 74 | block_called = false 75 | value = subject.get_or_set(key) do 76 | block_called = true 77 | end 78 | 79 | value.must_equal 'value' 80 | block_called.must_equal false 81 | end 82 | 83 | end 84 | 85 | describe 'value not yet present' do 86 | 87 | it 'evaluates the block and sets the result' do 88 | block_called = false 89 | subject.get_or_set(key) do 90 | block_called = true 91 | end 92 | 93 | block_called.must_equal true 94 | subject.data[key].must_equal true 95 | end 96 | 97 | end 98 | 99 | end 100 | 101 | describe 'cache purging' do 102 | 103 | let(:config) { { max_cache_keys: 3 } } 104 | 105 | it 'purges the cache when key size arrives at max' do 106 | subject.set('1', 'foo') 107 | subject.set('2', 'bar') 108 | subject.set('3', 'baz') 109 | subject.set('4', 'boz') 110 | 111 | subject.data.keys.size.must_equal 3 112 | end 113 | 114 | end 115 | 116 | end 117 | -------------------------------------------------------------------------------- /lib/device_detector/device.rb: -------------------------------------------------------------------------------- 1 | class DeviceDetector 2 | class Device < Parser 3 | 4 | # order is relevant for testing with fixtures 5 | DEVICE_NAMES = [ 6 | 'desktop', 7 | 'smartphone', 8 | 'tablet', 9 | 'feature phone', 10 | 'console', 11 | 'tv', 12 | 'car browser', 13 | 'smart display', 14 | 'camera', 15 | 'portable media player', 16 | 'phablet' 17 | ] 18 | 19 | def known? 20 | regex_meta.any? 21 | end 22 | 23 | def name 24 | ModelExtractor.new(user_agent, regex_meta).call 25 | end 26 | 27 | def type 28 | hbbtv? ? 'tv' : regex_meta[:device] 29 | end 30 | 31 | def brand 32 | regex_meta[:brand] 33 | end 34 | 35 | private 36 | 37 | # The order of files needs to be the same as the order of device 38 | # parser classes used in the piwik project. 39 | def filenames 40 | [ 41 | 'device/televisions.yml', 42 | 'device/consoles.yml', 43 | 'device/car_browsers.yml', 44 | 'device/cameras.yml', 45 | 'device/portable_media_player.yml', 46 | 'device/mobiles.yml', 47 | ] 48 | end 49 | 50 | def matching_regex 51 | from_cache([self.class.name, user_agent]) do 52 | regex_list = hbbtv? ? regexes_for_hbbtv : regexes_other 53 | regex = regex_list.find { |r| user_agent =~ r[:regex] } 54 | if regex && regex[:models] 55 | model_regex = regex[:models].find { |m| user_agent =~ m[:regex]} 56 | if model_regex 57 | regex = regex.merge(:regex_model => model_regex[:regex], :model => model_regex[:model], :brand => model_regex[:brand]) 58 | regex[:device] = model_regex[:device] if model_regex.key?(:device) 59 | regex.delete(:models) 60 | end 61 | end 62 | regex 63 | end 64 | end 65 | 66 | def hbbtv? 67 | @regex_hbbtv ||= build_regex('HbbTV/([1-9]{1}(?:\.[0-9]{1}){1,2})') 68 | user_agent =~ @regex_hbbtv 69 | end 70 | 71 | def regexes_for_hbbtv 72 | regexes.select { |r| r[:path] == :'device/televisions.yml' } 73 | end 74 | 75 | def regexes_other 76 | regexes.select { |r| r[:path] != :'device/televisions.yml' } 77 | end 78 | 79 | def parse_regexes(path, raw_regexes) 80 | raw_regexes.map do |brand, meta| 81 | fail "invalid device spec: #{meta.inspect}" unless meta[:regex].is_a? String 82 | meta[:regex] = build_regex(meta[:regex]) 83 | if meta.key?(:models) 84 | meta[:models].each do |model| 85 | fail "invalid model spec: #{model.inspect}" unless model[:regex].is_a? String 86 | model[:regex] = build_regex(model[:regex]) 87 | model[:brand] = brand.to_s unless model[:brand] 88 | end 89 | end 90 | meta[:path] = path 91 | meta 92 | end 93 | end 94 | 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /spec/fixtures/client/pim.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Outlook-Express/7.0 (MSIE 7.0; Windows NT 6.1; WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; AskTbORJ/5.15.9.29495; .NET4.0E; TmstmpExt) 3 | client: 4 | type: pim 5 | name: Outlook Express 6 | version: "7.0" 7 | - 8 | user_agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/7.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3; .NET CLR 1.1.4322; FDM; Tablet PC 2.0; .NET4.0E; Microsoft Outlook 14.0.7113; ms-office; MSOffice 14) 9 | client: 10 | type: pim 11 | name: Microsoft Outlook 12 | version: "14.0.7113" 13 | - 14 | user_agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130330 Thunderbird/17.0.5 15 | client: 16 | type: pim 17 | name: Thunderbird 18 | version: "17.0.5" 19 | - 20 | user_agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 Lightning/2.6.4 21 | client: 22 | type: pim 23 | name: Thunderbird 24 | version: "24.4.0" 25 | - 26 | user_agent: Airmail 1.4 rv:238 (Macintosh; Mac OS X 10.9.2; hr_HR) 27 | client: 28 | type: pim 29 | name: Airmail 30 | version: "1.4" 31 | - 32 | user_agent: Airmail 1.3.3 rv:237 (Macintosh; Mac OS X 10.9.2; en_US) 33 | client: 34 | type: pim 35 | name: Airmail 36 | version: "1.3.3" 37 | - 38 | user_agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Icedove/24.4.0 39 | client: 40 | type: pim 41 | name: Thunderbird 42 | version: "24.4.0" 43 | - 44 | user_agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Icedove/24.4.0 Lightning/2.6.5 45 | client: 46 | type: pim 47 | name: Thunderbird 48 | version: "24.4.0" 49 | - 50 | user_agent: Mozilla/4.0 (compatible; Lotus-Notes/6.0; Windows-NT) 51 | client: 52 | type: pim 53 | name: Lotus Notes 54 | version: "6.0" 55 | - 56 | user_agent: Barca/2.8.4400 57 | client: 58 | type: pim 59 | name: Barca 60 | version: "2.8.4400" 61 | - 62 | user_agent: BarcaPro/1.4 L.1001 63 | client: 64 | type: pim 65 | name: Barca 66 | version: "1.4" 67 | - 68 | user_agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.8) Gecko/20100317 Postbox/1.1.3 69 | client: 70 | type: pim 71 | name: Postbox 72 | version: "1.1.3" 73 | - 74 | user_agent: Postbox 1.0b14 (Windows/2009072715) 75 | client: 76 | type: pim 77 | name: Postbox 78 | version: "1.0" 79 | - 80 | user_agent: MailBar/1.3.2 (Mac OS X Version 10.11.1 (Build 15B42)) 81 | client: 82 | type: pim 83 | name: MailBar 84 | version: 1.3.2 85 | - 86 | user_agent: The Bat! 4.0.0.22 87 | client: 88 | type: pim 89 | name: The Bat! 90 | version: "4.0.0.22" 91 | - 92 | user_agent: The Bat! Voyager 4.0.18.4 93 | client: 94 | type: pim 95 | name: The Bat! 96 | version: "4.0.18.4" -------------------------------------------------------------------------------- /regexes/client/feed_readers.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | - regex: 'Akregator(?:/(\d+[\.\d]+))?' 9 | name: 'Akregator' 10 | version: '$1' 11 | url: 'http://userbase.kde.org/Akregator' 12 | type: 'Feed Reader' 13 | 14 | - regex: 'Apple-PubSub(?:/(\d+[\.\d]+))?' 15 | name: 'Apple PubSub' 16 | version: '$1' 17 | url: 'https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/pubsub.1.html' 18 | type: 'Feed Reader' 19 | 20 | - regex: 'FeedDemon(?:/(\d+[\.\d]+))?' 21 | name: 'FeedDemon' 22 | version: '$1' 23 | url: 'http://www.feeddemon.com/' 24 | type: 'Feed Reader' 25 | 26 | - regex: 'Feeddler(?:RSS|PRO)(?:[/ ](\d+[\.\d]+))?' 27 | name: 'Feeddler RSS Reader' 28 | version: '$1' 29 | url: 'http://www.chebinliu.com/projects/iphone/feeddler-rss-reader/' 30 | type: 'Feed Reader App' 31 | 32 | - regex: 'JetBrains Omea Reader(?:[/ ](\d+[\.\d]+))?' 33 | name: 'JetBrains Omea Reader' 34 | version: '$1' 35 | url: 'http://www.jetbrains.com/omea/reader/' 36 | type: 'Feed Reader' 37 | 38 | - regex: 'Liferea(?:[/ ](\d+[\.\d]+))?' 39 | name: 'Liferea' 40 | version: '$1' 41 | url: 'http://liferea.sf.net/' 42 | type: 'Feed Reader' 43 | 44 | - regex: 'NetNewsWire(?:[/ ](\d+[\.\d]+))?' 45 | name: 'NetNewsWire' 46 | version: '$1' 47 | url: 'http://netnewswireapp.com/' 48 | type: 'Feed Reader' 49 | 50 | - regex: 'NewsBlur (?:iPhone|iPad) App(?: v(\d+[\.\d]+))?' 51 | name: 'NewsBlur Mobile App' 52 | version: '$1' 53 | url: 'http://www.newsblur.com' 54 | type: 'Feed Reader App' 55 | 56 | - regex: 'NewsBlur(?:/(\d+[\.\d]+))' 57 | name: 'NewsBlur' 58 | version: '$1' 59 | url: 'http://www.newsblur.com' 60 | type: 'Feed Reader' 61 | 62 | - regex: 'newsbeuter(?:[/ ](\d+[\.\d]+))?' 63 | name: 'Newsbeuter' 64 | version: '$1' 65 | url: 'http://www.newsbeuter.org/' 66 | type: 'Feed Reader' 67 | 68 | - regex: 'Pulp(?:[/ ](\d+[\.\d]+))?' 69 | name: 'Pulp' 70 | version: '$1' 71 | url: 'http://www.acrylicapps.com/pulp/' 72 | type: 'Feed Reader App' 73 | 74 | - regex: 'ReadKit(?:[/ ](\d+[\.\d]+))?' 75 | name: 'ReadKit' 76 | version: '$1' 77 | url: 'http://readkitapp.com/' 78 | type: 'Feed Reader App' 79 | 80 | - regex: 'Reeder(?:[/ ](\d+[\.\d]+))?' 81 | name: 'Reeder' 82 | version: '$1' 83 | url: 'http://reederapp.com/' 84 | type: 'Feed Reader App' 85 | 86 | - regex: 'RSSBandit(?:[/ ](\d+[\.\d]+))?' 87 | name: 'RSS Bandit' 88 | version: '$1' 89 | url: 'http://www.rssbandit.org)' 90 | type: 'Feed Reader' 91 | 92 | - regex: 'RSS Junkie(?:[/ ](\d+[\.\d]+))?' 93 | name: 'RSS Junkie' 94 | version: '$1' 95 | url: 'https://play.google.com/store/apps/details?id=com.bitpowder.rssjunkie' 96 | type: 'Feed Reader App' 97 | 98 | - regex: 'RSSOwl(?:[/ ](\d+[\.\d]+))?' 99 | name: 'RSSOwl' 100 | version: '$1' 101 | url: 'http://www.rssowl.org/' 102 | type: 'Feed Reader' 103 | 104 | - regex: 'Stringer' 105 | name: 'Stringer' 106 | version: '' 107 | url: 'https://github.com/swanson/stringer' 108 | type: 'Feed Reader' 109 | -------------------------------------------------------------------------------- /spec/fixtures/detector/camera.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | user_agent: Mozilla/5.0 (Linux; U; Android 2.3.3; ja-jp; COOLPIX S800c Build/CP01_WW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 4 | os: 5 | name: Android 6 | short_name: AND 7 | version: "2.3.3" 8 | platform: 9 | client: 10 | type: browser 11 | name: Android Browser 12 | short_name: AN 13 | version: 14 | engine: WebKit 15 | device: 16 | type: camera 17 | brand: NN 18 | model: Coolpix S800c 19 | os_family: Android 20 | browser_family: Android Browser 21 | - 22 | user_agent: Mozilla/5.0 (Linux; U; Android 4.0; de-DE; EK-GC100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 23 | os: 24 | name: Android 25 | short_name: AND 26 | version: "4.0" 27 | platform: 28 | client: 29 | type: browser 30 | name: Android Browser 31 | short_name: AN 32 | version: 33 | engine: WebKit 34 | device: 35 | type: camera 36 | brand: SA 37 | model: GALAXY Camera 38 | os_family: Android 39 | browser_family: Android Browser 40 | - 41 | user_agent: Mozilla/5.0 (Linux; Android 4.1.2; EK-GC100 Build/JZO54K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Mobile Safari/537.36 OPR/15.0.1162.60140 42 | os: 43 | name: Android 44 | short_name: AND 45 | version: "4.1.2" 46 | platform: 47 | client: 48 | type: browser 49 | name: Opera Mobile 50 | short_name: OM 51 | version: "15.0.1162.60140" 52 | engine: Blink 53 | device: 54 | type: camera 55 | brand: SA 56 | model: GALAXY Camera 57 | os_family: Android 58 | browser_family: Opera 59 | - 60 | user_agent: Mozilla/5.0 (Linux; Android 4.3; EK-GC200 Build/JSS15J) AppleWebKit/537.36 (KHTML like Gecko) Chrome/35.0.1916.141 Mobile Safari/537.36 61 | os: 62 | name: Android 63 | short_name: AND 64 | version: "4.3" 65 | platform: 66 | client: 67 | type: browser 68 | name: Chrome Mobile 69 | short_name: CM 70 | version: "35.0.1916.141" 71 | engine: Blink 72 | device: 73 | type: camera 74 | brand: SA 75 | model: GALAXY Camera 2 76 | os_family: Android 77 | browser_family: Chrome 78 | - 79 | user_agent: Mozilla/5.0 (Linux; Android 4.1.2; EK-GC110 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19 80 | os: 81 | name: Android 82 | short_name: AND 83 | version: "4.1.2" 84 | platform: 85 | client: 86 | type: browser 87 | name: Chrome Mobile 88 | short_name: CM 89 | version: "18.0.1025.166" 90 | engine: WebKit 91 | device: 92 | type: camera 93 | brand: SA 94 | model: GALAXY Camera WiFi only 95 | os_family: Android 96 | browser_family: Chrome 97 | - 98 | user_agent: Mozilla/5.0 (Linux; Android 4.2.2; en-nz; SAMSUNG EK-GN120 Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Version/1.0 Chrome/18.0.1025.308 Mobile Safari/535.19 99 | os: 100 | name: Android 101 | short_name: AND 102 | version: "4.2.2" 103 | platform: 104 | client: 105 | type: browser 106 | name: Chrome Mobile 107 | short_name: CM 108 | version: "18.0.1025.308" 109 | engine: WebKit 110 | device: 111 | type: camera 112 | brand: SA 113 | model: GALAXY NX 114 | os_family: Android 115 | browser_family: Chrome 116 | -------------------------------------------------------------------------------- /spec/device_detector/concrete_user_agent_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../spec_helper' 2 | 3 | describe DeviceDetector do 4 | 5 | subject { DeviceDetector.new(user_agent) } 6 | 7 | alias :client :subject 8 | 9 | describe 'mobile iPhone 5S' do 10 | 11 | let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B440 [FBDV/iPhone6,1]' } 12 | 13 | describe '#device_name' do 14 | 15 | it 'returns device name' do 16 | client.device_name.must_equal 'iPhone 5S' 17 | end 18 | 19 | end 20 | 21 | describe '#device_type' do 22 | 23 | it 'returns the device type' do 24 | client.device_type.must_equal 'smartphone' 25 | end 26 | 27 | end 28 | 29 | end 30 | 31 | describe 'Ubuntu 10' do 32 | 33 | let(:user_agent) { 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16' } 34 | 35 | describe '#os_name' do 36 | 37 | it 'returns the OS name' do 38 | client.os_name.must_equal 'Ubuntu' 39 | end 40 | 41 | end 42 | 43 | end 44 | 45 | describe 'Mac OS X' do 46 | 47 | let(:user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36' } 48 | 49 | describe '#full_version' do 50 | 51 | it 'returns the correct OS version' do 52 | client.os_full_version.must_equal '10.10.1' 53 | end 54 | 55 | end 56 | 57 | end 58 | 59 | describe 'Chrome on Windows' do 60 | 61 | describe '32bit' do 62 | 63 | let(:user_agent) { 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.103 Safari/537.36' } 64 | 65 | it 'returns the correct client name' do 66 | client.name.must_equal 'Chrome' 67 | end 68 | 69 | it 'recognizes the device name' do 70 | client.device_name.must_be_nil 71 | end 72 | 73 | it 'recognizes the device type' do 74 | client.device_type.must_equal "desktop" 75 | end 76 | 77 | end 78 | 79 | describe '64bit' do 80 | 81 | let(:user_agent) { 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36' } 82 | 83 | it 'returns the correct client name' do 84 | client.name.must_equal 'Chrome' 85 | end 86 | 87 | it 'recognizes the device name' do 88 | client.device_name.must_be_nil 89 | end 90 | 91 | it 'recognizes the device type' do 92 | client.device_type.must_equal "desktop" 93 | end 94 | 95 | end 96 | 97 | end 98 | 99 | describe 'recognize and ignore sprd- prefix' do 100 | 101 | let(:user_agent) { 'sprd-Galaxy-S5/1.0 Linux/2.6.35.7 Android/4.4.4 Release/11.29.2014 Browser/AppleWebKit533.1 (KHTML, like Gecko) Mozilla/5.0 Mobile' } 102 | 103 | it 'returns the correct client name' do 104 | client.name.must_equal "Android Browser" 105 | end 106 | 107 | it 'recognizes the device name' do 108 | client.device_name.must_equal "GALAXY S5" 109 | end 110 | 111 | it 'recognizes the device type' do 112 | client.device_type.must_equal "smartphone" 113 | end 114 | 115 | end 116 | 117 | describe 'remove TD suffix from model' do 118 | 119 | let(:user_agent) { 'Lenovo-A398t+_TD/S100 Linux/3.4.5 Android/4.1.2 Release/09.10.2013 Browser/AppleWebKit534.30 Mobile Safari/534.30' } 120 | 121 | it 'returns the correct client name' do 122 | client.name.must_equal "Android Browser" 123 | end 124 | 125 | it 'recognizes the device name' do 126 | client.device_name.must_equal "A398t+" 127 | end 128 | 129 | it 'recognizes the device type' do 130 | client.device_type.must_equal "smartphone" 131 | end 132 | 133 | end 134 | 135 | end 136 | 137 | -------------------------------------------------------------------------------- /spec/fixtures/detector/mobile_apps.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Pulse/4.0.5 (iPhone; iOS 7.0.6; Scale/2.00) 3 | os: 4 | name: iOS 5 | short_name: IOS 6 | version: "7.0.6" 7 | platform: 8 | client: 9 | type: mobile app 10 | name: Pulse 11 | version: "4.0.5" 12 | device: 13 | type: smartphone 14 | brand: AP 15 | model: iPhone 16 | os_family: iOS 17 | browser_family: Unknown 18 | - 19 | user_agent: WhatsApp/2.6.4 iPhone_OS/4.3.3 Device/iPhone_4 20 | os: 21 | name: iOS 22 | short_name: IOS 23 | version: "4.3.3" 24 | platform: 25 | client: 26 | type: mobile app 27 | name: WhatsApp 28 | version: "2.6.4" 29 | device: 30 | type: smartphone 31 | brand: AP 32 | model: iPhone 33 | os_family: iOS 34 | browser_family: Unknown 35 | - 36 | user_agent: AndroidDownloadManager/4.1.1 (Linux; U; Android 4.1.1; MB886 Build/9.8.0Q-97_MB886_FFW-20) 37 | os: 38 | name: Android 39 | short_name: AND 40 | version: "4.1.1" 41 | platform: 42 | client: 43 | type: mobile app 44 | name: AndroidDownloadManager 45 | version: "4.1.1" 46 | device: 47 | type: smartphone 48 | brand: MR 49 | model: MB886 50 | os_family: Android 51 | browser_family: Unknown 52 | - 53 | user_agent: com.google.android.youtube/2.4.4(Linux; U; Android 2.3.5; en_US; SCH-I500 Build/GINGERBREAD) gzip 54 | os: 55 | name: Android 56 | short_name: AND 57 | version: "2.3.5" 58 | platform: 59 | client: 60 | type: mobile app 61 | name: YouTube 62 | version: "2.4.4" 63 | device: 64 | type: smartphone 65 | brand: SA 66 | model: SCH-I500 67 | os_family: Android 68 | browser_family: Unknown 69 | - 70 | user_agent: NS/3.3.1 (Linux; U; Android 5.0.1; en-in; phone/Nexus 5 Build/LRX22C; Density/480; gzip) com.google.android.apps.magazines/2014102707 71 | os: 72 | name: Android 73 | short_name: AND 74 | version: "5.0.1" 75 | platform: 76 | client: 77 | type: mobile app 78 | name: Google Play Newsstand 79 | version: 80 | device: 81 | type: smartphone 82 | brand: GO 83 | model: Nexus 5 84 | os_family: Android 85 | browser_family: Unknown 86 | - 87 | user_agent: Mozilla/5.0 (iPad3,6; iPad; U; CPU OS 7_1 like Mac OS X; en_US) com.google.GooglePlus/33839 (KHTML, like Gecko) Mobile/P103AP (gzip) 88 | os: 89 | name: iOS 90 | short_name: IOS 91 | version: "7.1" 92 | platform: 93 | client: 94 | type: mobile app 95 | name: Google Plus 96 | version: 97 | device: 98 | type: tablet 99 | brand: AP 100 | model: iPad 4 101 | os_family: iOS 102 | browser_family: Unknown 103 | - 104 | user_agent: '[FBAN/FB4A;FBAV/26.0.0.22.16;FBBV/6590638;FBDM/{density=1.5,width=791,height=480};FBLC/en_US;FBCR/SmarTone HK;FBMF/Sony;FBBD/Sony;FBPN/com.facebook.katana;FBDV/C1905;FBSV/4.1.2;FBOP/19;FBCA/armeabi-v7a:armeabi;]' 105 | os: [ ] 106 | client: 107 | type: mobile app 108 | name: Facebook 109 | version: "26.0.0.22.16" 110 | device: 111 | type: smartphone 112 | brand: SO 113 | model: Xperia M 114 | os_family: Unknown 115 | browser_family: Unknown 116 | - 117 | user_agent: Mozilla/5.0 (iPhone; CPU iPhone OS 8_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12D508 Safari Line/5.9.5 118 | os: 119 | name: iOS 120 | short_name: IOS 121 | version: "8.2" 122 | platform: 123 | client: 124 | type: mobile app 125 | name: Line 126 | version: "5.9.5" 127 | device: 128 | type: smartphone 129 | brand: AP 130 | model: iPhone 131 | os_family: iOS 132 | browser_family: Unknown 133 | - 134 | user_agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_2_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13D15 Safari Line/5.10.0 135 | os: 136 | name: iOS 137 | short_name: IOS 138 | version: "9.2.1" 139 | platform: 140 | client: 141 | type: mobile app 142 | name: Line 143 | version: "5.10.0" 144 | device: 145 | type: smartphone 146 | brand: AP 147 | model: iPhone 148 | os_family: iOS 149 | browser_family: Unknown 150 | -------------------------------------------------------------------------------- /spec/device_detector_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative 'spec_helper' 2 | 3 | describe DeviceDetector do 4 | 5 | subject { DeviceDetector.new(user_agent) } 6 | 7 | alias :client :subject 8 | 9 | describe 'known user agent' do 10 | 11 | describe 'desktop chrome browser' do 12 | 13 | let(:user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.69' } 14 | 15 | describe '#name' do 16 | 17 | it 'returns the name' do 18 | client.name.must_equal 'Chrome' 19 | end 20 | 21 | end 22 | 23 | describe '#full_version' do 24 | 25 | it 'returns the full version' do 26 | client.full_version.must_equal '30.0.1599.69' 27 | end 28 | 29 | end 30 | 31 | describe '#os_name' do 32 | 33 | it 'returns the operating system name' do 34 | client.os_name.must_equal 'Mac' 35 | end 36 | 37 | end 38 | 39 | describe '#os_full_version' do 40 | 41 | it 'returns the operating system full version' do 42 | client.os_full_version.must_equal '10.8.5' 43 | end 44 | 45 | end 46 | 47 | describe '#known?' do 48 | 49 | it 'returns true' do 50 | client.known?.must_equal true 51 | end 52 | 53 | end 54 | 55 | describe '#bot?' do 56 | 57 | it 'returns false' do 58 | client.bot?.must_equal false 59 | end 60 | 61 | end 62 | 63 | describe '#bot_name' do 64 | 65 | it 'returns nil' do 66 | client.bot_name.must_be_nil 67 | end 68 | 69 | end 70 | 71 | end 72 | 73 | end 74 | 75 | describe 'unknown user agent' do 76 | 77 | let(:user_agent) { 'garbage123' } 78 | 79 | describe '#name' do 80 | 81 | it 'returns nil' do 82 | client.name.must_be_nil 83 | end 84 | 85 | end 86 | 87 | describe '#full_version' do 88 | 89 | it 'returns nil' do 90 | client.full_version.must_be_nil 91 | end 92 | 93 | end 94 | 95 | describe '#os_name' do 96 | 97 | it 'returns nil' do 98 | client.os_name.must_be_nil 99 | end 100 | 101 | end 102 | 103 | describe '#os_full_version' do 104 | 105 | it 'returns nil' do 106 | client.os_full_version.must_be_nil 107 | end 108 | 109 | end 110 | 111 | describe '#known?' do 112 | 113 | it 'returns false' do 114 | client.known?.must_equal false 115 | end 116 | 117 | end 118 | 119 | describe '#bot?' do 120 | 121 | it 'returns false' do 122 | client.bot?.must_equal false 123 | end 124 | 125 | end 126 | 127 | describe '#bot_name' do 128 | 129 | it 'returns nil' do 130 | client.bot_name.must_be_nil 131 | end 132 | 133 | end 134 | 135 | end 136 | 137 | describe 'bot' do 138 | 139 | let(:user_agent) { 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' } 140 | 141 | describe '#name' do 142 | 143 | it 'returns nil' do 144 | client.name.must_be_nil 145 | end 146 | 147 | end 148 | 149 | describe '#full_version' do 150 | 151 | it 'returns nil' do 152 | client.full_version.must_be_nil 153 | end 154 | 155 | end 156 | 157 | describe '#os_name' do 158 | 159 | it 'returns nil' do 160 | client.os_name.must_be_nil 161 | end 162 | 163 | end 164 | 165 | describe '#os_full_version' do 166 | 167 | it 'returns nil' do 168 | client.os_full_version.must_be_nil 169 | end 170 | 171 | end 172 | 173 | describe '#known?' do 174 | 175 | it 'returns false' do 176 | client.known?.must_equal false 177 | end 178 | 179 | end 180 | 181 | describe '#bot?' do 182 | 183 | it 'returns true' do 184 | client.bot?.must_equal true 185 | end 186 | 187 | end 188 | 189 | describe '#bot_name' do 190 | 191 | it 'returns the name of the bot' do 192 | client.bot_name.must_equal 'Googlebot' 193 | end 194 | 195 | end 196 | 197 | end 198 | end 199 | -------------------------------------------------------------------------------- /spec/fixtures/detector/portable_media_player.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | user_agent: Mozilla/5.0 (iPod; U; CPU iPhone OS 4_2_1 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/8C148 4 | os: 5 | name: iOS 6 | short_name: IOS 7 | version: "4.2.1" 8 | platform: 9 | client: 10 | type: browser 11 | name: Mobile Safari 12 | short_name: MF 13 | version: 14 | engine: WebKit 15 | device: 16 | type: portable media player 17 | brand: AP 18 | model: iPod Touch 19 | os_family: iOS 20 | browser_family: Safari 21 | - 22 | user_agent: Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_0 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Mobile/4B2086 23 | os: 24 | name: iOS 25 | short_name: IOS 26 | version: "4.3.0" 27 | platform: 28 | client: 29 | type: browser 30 | name: Mobile Safari 31 | short_name: MF 32 | version: 33 | engine: WebKit 34 | device: 35 | type: portable media player 36 | brand: AP 37 | model: iPod Touch 38 | os_family: iOS 39 | browser_family: Safari 40 | - 41 | user_agent: Mozilla/5.0 (Linux; U; Android 2.3; fr-fr; COWON D3 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 42 | os: 43 | name: Android 44 | short_name: AND 45 | version: "2.3" 46 | platform: 47 | client: 48 | type: browser 49 | name: Android Browser 50 | short_name: AN 51 | version: 52 | engine: WebKit 53 | device: 54 | type: portable media player 55 | brand: CW 56 | model: D3 57 | os_family: Android 58 | browser_family: Android Browser 59 | - 60 | user_agent: Mozilla/5.0 (Linux; U; Android 2.3.5; fr-fr; COWON Z2 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 61 | os: 62 | name: Android 63 | short_name: AND 64 | version: "2.3.5" 65 | platform: 66 | client: 67 | type: browser 68 | name: Android Browser 69 | short_name: AN 70 | version: 71 | engine: WebKit 72 | device: 73 | type: portable media player 74 | brand: CW 75 | model: Z2 76 | os_family: Android 77 | browser_family: Android Browser 78 | - 79 | user_agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 6.12; Microsoft ZuneHD 4.3) 80 | os: 81 | name: Windows CE 82 | short_name: WCE 83 | version: 84 | platform: 85 | client: 86 | type: browser 87 | name: IE Mobile 88 | short_name: IM 89 | version: "6.12" 90 | engine: Trident 91 | device: 92 | type: portable media player 93 | brand: MS 94 | model: Zune HD 95 | os_family: Windows Mobile 96 | browser_family: Internet Explorer 97 | - 98 | user_agent: Mozilla/5.0 (Linux; U; Android 2.1-update1; ja-jp; Panasonic SV-MV100 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17 99 | os: 100 | name: Android 101 | short_name: AND 102 | version: "2.1" 103 | platform: 104 | client: 105 | type: browser 106 | name: Android Browser 107 | short_name: AN 108 | version: 109 | engine: WebKit 110 | device: 111 | type: portable media player 112 | brand: PA 113 | model: SV-MV100 114 | os_family: Android 115 | browser_family: Android Browser 116 | - 117 | user_agent: Mozilla/5.0 (Linux; U; Android 2.3.6; ko-kr; YP-GB1 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 118 | os: 119 | name: Android 120 | short_name: AND 121 | version: "2.3.6" 122 | platform: 123 | client: 124 | type: browser 125 | name: Android Browser 126 | short_name: AN 127 | version: 128 | engine: WebKit 129 | device: 130 | type: portable media player 131 | brand: SA 132 | model: Galaxy Player 4.0 133 | os_family: Android 134 | browser_family: Android Browser 135 | - 136 | user_agent: Mozilla/5.0 (Linux; U; Android 2.3.6; it-it; YP-GI1 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 137 | os: 138 | name: Android 139 | short_name: AND 140 | version: "2.3.6" 141 | platform: 142 | client: 143 | type: browser 144 | name: Android Browser 145 | short_name: AN 146 | version: 147 | engine: WebKit 148 | device: 149 | type: portable media player 150 | brand: SA 151 | model: Galaxy Player 4.2 152 | os_family: Android 153 | browser_family: Android Browser 154 | -------------------------------------------------------------------------------- /spec/fixtures/detector/mediaplayer.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.28) Gecko/20130316 Songbird/1.12.1 (20140112193149) 3 | os: 4 | name: GNU/Linux 5 | short_name: LIN 6 | version: 7 | platform: x86 8 | client: 9 | type: mediaplayer 10 | name: Songbird 11 | version: "1.12.1" 12 | device: 13 | type: desktop 14 | brand: 15 | model: 16 | os_family: GNU/Linux 17 | browser_family: Unknown 18 | - 19 | user_agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.28) Gecko/20130316 Nightingale/1.12.2 (20140112193149) 20 | os: 21 | name: GNU/Linux 22 | short_name: LIN 23 | version: 24 | platform: x86 25 | client: 26 | type: mediaplayer 27 | name: Nightingale 28 | version: "1.12.2" 29 | device: 30 | type: desktop 31 | brand: 32 | model: 33 | os_family: GNU/Linux 34 | browser_family: Unknown 35 | - 36 | user_agent: iTunes/10.2.1 (Macintosh; Intel Mac OS X 10.7) AppleWebKit/534.20.8 37 | os: 38 | name: Mac 39 | short_name: MAC 40 | version: "10.7" 41 | platform: 42 | client: 43 | type: mediaplayer 44 | name: iTunes 45 | version: "10.2.1" 46 | device: 47 | type: desktop 48 | brand: 49 | model: 50 | os_family: Mac 51 | browser_family: Unknown 52 | - 53 | user_agent: iTunes/10.2.1 (Windows; Microsoft Windows 7 Enterprise Edition Service Pack 1 (Build 7601)) AppleWebKit/533.20.25 54 | os: 55 | name: Windows 56 | short_name: WIN 57 | version: "7" 58 | platform: 59 | client: 60 | type: mediaplayer 61 | name: iTunes 62 | version: "10.2.1" 63 | device: 64 | type: desktop 65 | brand: 66 | model: 67 | os_family: Windows 68 | browser_family: Unknown 69 | - 70 | user_agent: SAMSUNG-GT-S3850/S3850CXKD1 SHP/VPP/R5 Dolfin/2.0 NexPlayer/3.0 SMM-MMS/1.2.0 profile/MIDP-2.1 configuration/CLDC-1.1 OPN-B 71 | os: [ ] 72 | client: 73 | type: mediaplayer 74 | name: NexPlayer 75 | version: "3.0" 76 | device: 77 | type: smartphone 78 | brand: SA 79 | model: GT-S3850 80 | os_family: Unknown 81 | browser_family: Unknown 82 | - 83 | user_agent: FlyCast/1.34 (BlackBerry; 8330/4.5.0.131 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/-1) 84 | os: 85 | name: BlackBerry OS 86 | short_name: BLB 87 | version: 88 | platform: 89 | client: 90 | type: mediaplayer 91 | name: FlyCast 92 | version: "1.34" 93 | device: 94 | type: smartphone 95 | brand: RM 96 | model: BlackBerry 97 | os_family: BlackBerry 98 | browser_family: Unknown 99 | - 100 | user_agent: NSPlayer/10.0.0.4072 WMFSDK/10.0 101 | os: [ ] 102 | client: 103 | type: mediaplayer 104 | name: Windows Media Player 105 | version: "10.0.0.4072" 106 | device: 107 | type: 108 | brand: 109 | model: 110 | os_family: Unknown 111 | browser_family: Unknown 112 | - 113 | user_agent: XBMC/9.04 r19840 (Mac OS X; Darwin 9.6.0; http://www.xbmc.org) 114 | os: 115 | name: Mac 116 | short_name: MAC 117 | version: 118 | platform: 119 | client: 120 | type: mediaplayer 121 | name: XBMC 122 | version: "9.04" 123 | device: 124 | type: desktop 125 | brand: 126 | model: 127 | os_family: Mac 128 | browser_family: Unknown 129 | - 130 | user_agent: SubStream/0.7 CFNetwork/485.12.30 Darwin/10.4.0 131 | os: 132 | name: iOS 133 | short_name: IOS 134 | version: "4.2" 135 | platform: 136 | client: 137 | type: mediaplayer 138 | name: SubStream 139 | version: "0.7" 140 | device: 141 | type: 142 | brand: AP 143 | model: 144 | os_family: iOS 145 | browser_family: Unknown 146 | - 147 | user_agent: Samsung GT-I9505 stagefright/1.2 (Linux;Android 4.4.2) 148 | os: 149 | name: Android 150 | short_name: AND 151 | version: "4.4.2" 152 | platform: 153 | client: 154 | type: mediaplayer 155 | name: Stagefright 156 | version: "1.2" 157 | device: 158 | type: smartphone 159 | brand: SA 160 | model: GALAXY S4 161 | os_family: Android 162 | browser_family: Unknown 163 | - 164 | user_agent: Kodi/14.0 (Macintosh; Intel Mac OS X 10_10_3) App_Bitness/64 Version/14.0-Git:2014-12-23-ad747d9-dirty 165 | os: 166 | name: Mac 167 | short_name: MAC 168 | version: "10.10.3" 169 | platform: 170 | client: 171 | type: mediaplayer 172 | name: Kodi 173 | version: "14.0" 174 | device: 175 | type: desktop 176 | brand: 177 | model: 178 | os_family: Mac 179 | browser_family: Unknown 180 | -------------------------------------------------------------------------------- /spec/device_detector/device_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative '../spec_helper' 2 | 3 | describe DeviceDetector::Device do 4 | 5 | subject { DeviceDetector::Device.new(user_agent) } 6 | 7 | alias :device :subject 8 | 9 | describe '#name' do 10 | 11 | describe 'when models are nested' do 12 | let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B466 [FBDV/iPhone7,2]' } 13 | 14 | it 'finds an Apple iPhone 6' do 15 | device.name.must_equal 'iPhone 6' 16 | end 17 | end 18 | 19 | describe 'when models are NOT nested' do 20 | let(:user_agent) { 'AIRNESS-AIR99/REV 2.2.1/Teleca Q03B1' } 21 | 22 | it 'finds an Airness AIR99' do 23 | device.name.must_equal 'AIR99' 24 | end 25 | end 26 | 27 | describe 'when it cannot find a device name' do 28 | let(:user_agent) { 'UNKNOWN MODEL NAME' } 29 | 30 | it 'returns nil' do 31 | device.name.must_be_nil 32 | end 33 | end 34 | 35 | end 36 | 37 | describe '#type' do 38 | 39 | describe 'when models are nested' do 40 | let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B466 [FBDV/iPhone7,2]' } 41 | 42 | it 'finds device of Apple iPhone 6' do 43 | device.type.must_equal 'smartphone' 44 | end 45 | end 46 | 47 | describe 'when models are NOT nested' do 48 | let(:user_agent) { 'AIRNESS-AIR99/REV 2.2.1/Teleca Q03B1' } 49 | 50 | it 'finds the device of Airness AIR99' do 51 | device.type.must_equal 'feature phone' 52 | end 53 | end 54 | 55 | describe 'when it cannot find a device type' do 56 | let(:user_agent) { 'UNKNOWN MODEL TYPE' } 57 | 58 | it 'returns nil' do 59 | device.type.must_be_nil 60 | end 61 | 62 | end 63 | 64 | describe 'device not specified in nested block' do 65 | 66 | let(:user_agent) { 'Mozilla/5.0 (Linux; Android 4.4.2; es-us; SAMSUNG SM-G900F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)' } 67 | 68 | it 'falls back to top-level device' do 69 | device.type.must_equal 'smartphone' 70 | end 71 | 72 | end 73 | 74 | end 75 | 76 | describe 'concrete device types' do 77 | 78 | describe 'mobiles' do 79 | 80 | let(:user_agent) { 'Mozilla/5.0 (Linux; Android 4.4.2; es-us; SAMSUNG SM-G900F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)' } 81 | 82 | it 'identifies the device' do 83 | device.name.must_equal 'GALAXY S5' 84 | device.type.must_equal 'smartphone' 85 | device.brand.must_equal 'Samsung' 86 | end 87 | 88 | end 89 | 90 | describe 'cameras' do 91 | 92 | let(:user_agent) { 'Mozilla/5.0 (Linux; U; Android 4.0; xx-xx; EK-GC100 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' } 93 | 94 | it 'identifies the device' do 95 | device.name.must_equal 'GALAXY Camera' 96 | device.type.must_equal 'camera' 97 | device.brand.must_equal 'Samsung' 98 | end 99 | 100 | end 101 | 102 | describe 'car browsers' do 103 | 104 | let(:user_agent) { 'Mozilla/5.0 (X11; Linux) AppleWebKit/534.34 (KHTML, like Gecko) QtCarBrowser Safari/534.34' } 105 | 106 | it 'identifies the device' do 107 | device.name.must_equal 'Model S' 108 | device.type.must_equal 'car browser' 109 | device.brand.must_be_nil 110 | end 111 | 112 | end 113 | 114 | describe '(gaming) consoles' do 115 | 116 | let(:user_agent) { 'Opera/9.30 (Nintendo Wii; U; ; 2047-7;en)' } 117 | 118 | it 'identifies the device' do 119 | device.name.must_equal 'Wii' 120 | device.type.must_equal 'console' 121 | device.brand.must_be_nil 122 | end 123 | 124 | end 125 | 126 | describe 'portable media players' do 127 | 128 | let(:user_agent) { 'Mozilla/5.0 (iPod touch; CPU iPhone OS 7_0_6 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B651 Safari/9537.53' } 129 | 130 | it 'identifies the device' do 131 | device.name.must_equal 'iPod Touch' 132 | device.type.must_equal 'portable media player' 133 | device.brand.must_equal 'Apple' 134 | end 135 | 136 | end 137 | 138 | describe 'televisions' do 139 | 140 | let(:user_agent) { 'Mozilla/5.0 (Unknown; Linux armv7l) AppleWebKit/537.1+ (KHTML, like Gecko) Safari/537.1+ HbbTV/1.1.1 ( ;LGE ;NetCast 4.0 ;03.10.81 ;1.0M ;)' } 141 | 142 | it 'identifies the device' do 143 | device.name.must_equal 'NetCast 4.0' 144 | device.type.must_equal 'tv' 145 | device.brand.must_equal 'LG' 146 | end 147 | 148 | end 149 | end 150 | 151 | end 152 | -------------------------------------------------------------------------------- /spec/fixtures/client/mediaplayer.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.28) Gecko/20130316 Songbird/1.12.1 (20140112193149) 3 | client: 4 | type: mediaplayer 5 | name: Songbird 6 | version: "1.12.1" 7 | - 8 | user_agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.28) Gecko/20130316 Nightingale/1.12.2 (20140112193149) 9 | client: 10 | type: mediaplayer 11 | name: Nightingale 12 | version: "1.12.2" 13 | - 14 | user_agent: iTunes/10.2.1 (Macintosh; Intel Mac OS X 10.7) AppleWebKit/534.20.8 15 | client: 16 | type: mediaplayer 17 | name: iTunes 18 | version: "10.2.1" 19 | - 20 | user_agent: iTunes/10.2.1 (Windows; Microsoft Windows 7 Enterprise Edition Service Pack 1 (Build 7601)) AppleWebKit/533.20.25 21 | client: 22 | type: mediaplayer 23 | name: iTunes 24 | version: "10.2.1" 25 | - 26 | user_agent: VLC/2.1.0 LibVLC/2.1.0 27 | client: 28 | type: mediaplayer 29 | name: VLC 30 | version: "2.1.0" 31 | - 32 | user_agent: LibVLC/2.2.3 (LIVE555 Streaming Media v2015.10.12) 33 | client: 34 | type: mediaplayer 35 | name: VLC 36 | version: "2.2.3" 37 | - 38 | user_agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; FunWebProducts; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; Windows-Media-Player/10.00.00.3990) 39 | client: 40 | type: mediaplayer 41 | name: Windows Media Player 42 | version: "10.00.00.3990" 43 | - 44 | user_agent: Windows-Media-Player/11.0.6001.7000 45 | client: 46 | type: mediaplayer 47 | name: Windows Media Player 48 | version: "11.0.6001.7000" 49 | - 50 | user_agent: SAMSUNG-GT-S3850/S3850CXKD1 SHP/VPP/R5 Dolfin/2.0 NexPlayer/3.0 SMM-MMS/1.2.0 profile/MIDP-2.1 configuration/CLDC-1.1 OPN-B 51 | client: 52 | type: mediaplayer 53 | name: NexPlayer 54 | version: "3.0" 55 | - 56 | user_agent: Banshee 1.5.1 (http://banshee-project.org/) 57 | client: 58 | type: mediaplayer 59 | name: Banshee 60 | version: "1.5.1" 61 | - 62 | user_agent: Banshee/2.6.2 (http://banshee-project.org/) 63 | client: 64 | type: mediaplayer 65 | name: Banshee 66 | version: "2.6.2" 67 | - 68 | user_agent: QuickTime/7.6.6 (qtver=7.6.6;cpu=IA32;os=Mac 10.6.8) 69 | client: 70 | type: mediaplayer 71 | name: QuickTime 72 | version: "7.6.6" 73 | - 74 | user_agent: QuickTime.7.7.4 (qtver=7.7.4;os=Windows NT 6.0Service Pack 2) 75 | client: 76 | type: mediaplayer 77 | name: QuickTime 78 | version: "7.7.4" 79 | - 80 | user_agent: QuickTime (qtver=7.0.2a26;os=Windows NT 6.0) 81 | client: 82 | type: mediaplayer 83 | name: QuickTime 84 | version: "7.0.2" 85 | - 86 | user_agent: QuickTime E-/7.7.5 (qtver=7.7.5;os=Windows NT 6.1) 87 | client: 88 | type: mediaplayer 89 | name: QuickTime 90 | version: "7.7.5" 91 | - 92 | user_agent: FlyCast/1.34 (BlackBerry; 8330/4.5.0.131 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/-1) 93 | client: 94 | type: mediaplayer 95 | name: FlyCast 96 | version: "1.34" 97 | - 98 | user_agent: XBMC/9.04 r19840 (Mac OS X; Darwin 9.6.0; http://www.xbmc.org) 99 | client: 100 | type: mediaplayer 101 | name: XBMC 102 | version: "9.04" 103 | - 104 | user_agent: XBMC/9.04-beta1 r19639 (Windows; Windows XP Professional Service Pack 2 build 2600; http://www.xbmc.org) 105 | client: 106 | type: mediaplayer 107 | name: XBMC 108 | version: "9.04" 109 | - 110 | user_agent: SubStream/0.7 CFNetwork/485.12.30 Darwin/10.4.0 111 | client: 112 | type: mediaplayer 113 | name: SubStream 114 | version: "0.7" 115 | - 116 | user_agent: MediaMonkey 4.1.1.1703 117 | client: 118 | type: mediaplayer 119 | name: MediaMonkey 120 | version: "4.1.1.1703" 121 | - 122 | user_agent: Clementine 1.2.2 123 | client: 124 | type: mediaplayer 125 | name: Clementine 126 | version: "1.2.2" 127 | - 128 | user_agent: WAFA/1.2.10 (Linux; Android 4.1; Winamp) Replicant/1.0 129 | client: 130 | type: mediaplayer 131 | name: Winamp 132 | version: 133 | - 134 | user_agent: WinampMPEG/5.66, Ultravox/2.1 135 | client: 136 | type: mediaplayer 137 | name: Winamp 138 | version: "5.66" 139 | - 140 | user_agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9) Gecko Miro/2.0.4 (http://www.getmiro.com/) 141 | client: 142 | type: mediaplayer 143 | name: Miro 144 | version: "2.0.4" 145 | - 146 | user_agent: Miro/3.0.1 (http://www.getmiro.com/; Darwin 8.11.1 i386) 147 | client: 148 | type: mediaplayer 149 | name: Miro 150 | version: "3.0.1" 151 | - 152 | user_agent: Kodi/14.0 (Macintosh; Intel Mac OS X 10_10_3) App_Bitness/64 Version/14.0-Git:2014-12-23-ad747d9-dirty 153 | client: 154 | type: mediaplayer 155 | name: Kodi 156 | version: "14.0" 157 | - 158 | user_agent: Instacast/2380 CFNetwork/720.2.4 Darwin/14.1.0 (x86_64) 159 | client: 160 | type: mediaplayer 161 | name: Instacast 162 | version: "2380" 163 | - 164 | user_agent: Instacast/4.1.2 CFNetwork/672.0.8 Darwin/14.0.0 165 | client: 166 | type: mediaplayer 167 | name: Instacast 168 | version: "4.1.2" 169 | -------------------------------------------------------------------------------- /lib/device_detector.rb: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | 3 | require 'device_detector/version' 4 | require 'device_detector/metadata_extractor' 5 | require 'device_detector/version_extractor' 6 | require 'device_detector/model_extractor' 7 | require 'device_detector/name_extractor' 8 | require 'device_detector/memory_cache' 9 | require 'device_detector/parser' 10 | require 'device_detector/bot' 11 | require 'device_detector/client' 12 | require 'device_detector/device' 13 | require 'device_detector/os' 14 | 15 | class DeviceDetector 16 | 17 | attr_reader :user_agent 18 | 19 | def initialize(user_agent) 20 | @user_agent = user_agent 21 | end 22 | 23 | def name 24 | client.name 25 | end 26 | 27 | def full_version 28 | client.full_version 29 | end 30 | 31 | def os_name 32 | os.name 33 | end 34 | 35 | def os_full_version 36 | os.full_version 37 | end 38 | 39 | def device_name 40 | device.name 41 | end 42 | 43 | def device_brand 44 | device.brand 45 | end 46 | 47 | def device_type 48 | t = device.type 49 | 50 | if t.nil? && android_tablet_fragment? || opera_tablet? 51 | t = 'tablet' 52 | end 53 | 54 | if t.nil? && android_mobile_fragment? 55 | t = 'smartphone' 56 | end 57 | 58 | # Android up to 3.0 was designed for smartphones only. But as 3.0, 59 | # which was tablet only, was published too late, there were a 60 | # bunch of tablets running with 2.x With 4.0 the two trees were 61 | # merged and it is for smartphones and tablets 62 | # 63 | # So were are expecting that all devices running Android < 2 are 64 | # smartphones Devices running Android 3.X are tablets. Device type 65 | # of Android 2.X and 4.X+ are unknown 66 | if t.nil? && os.short_name == 'AND' && os.full_version && !os.full_version.empty? 67 | if os.full_version < '2' 68 | t = 'smartphone' 69 | elsif os.full_version >= '3' && os.full_version < '4' 70 | t = 'tablet' 71 | end 72 | end 73 | 74 | # All detected feature phones running android are more likely a smartphone 75 | if t == 'feature phone' && os.family == 'Android' 76 | t = 'smartphone' 77 | end 78 | 79 | # According to http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx 80 | # Internet Explorer 10 introduces the "Touch" UA string token. If this token is present at the end of the 81 | # UA string, the computer has touch capability, and is running Windows 8 (or later). 82 | # This UA string will be transmitted on a touch-enabled system running Windows 8 (RT) 83 | # 84 | # As most touch enabled devices are tablets and only a smaller part are desktops/notebooks we assume that 85 | # all Windows 8 touch devices are tablets. 86 | if t.nil? && touch_enabled? && 87 | (os.short_name == 'WRT' || (os.short_name == 'WIN' && os.full_version && os.full_version >= '8')) 88 | t = 'tablet' 89 | end 90 | 91 | if opera_tv_store? 92 | t = 'tv' 93 | end 94 | 95 | if t.nil? && ['Kylo', 'Espial TV Browser'].include?(client.name) 96 | t = 'tv' 97 | end 98 | 99 | # set device type to desktop for all devices running a desktop os that were 100 | # not detected as an other device type 101 | if t.nil? && os.desktop? && !puffin_browser? 102 | t = 'desktop' 103 | end 104 | 105 | t 106 | end 107 | 108 | def known? 109 | client.known? 110 | end 111 | 112 | def bot? 113 | bot.bot? 114 | end 115 | 116 | def bot_name 117 | bot.name 118 | end 119 | 120 | class << self 121 | 122 | class Configuration 123 | attr_accessor :max_cache_keys 124 | 125 | def to_hash 126 | { 127 | max_cache_keys: max_cache_keys 128 | } 129 | end 130 | end 131 | 132 | def config 133 | @config ||= Configuration.new 134 | end 135 | 136 | def cache 137 | @cache ||= MemoryCache.new(config.to_hash) 138 | end 139 | 140 | def configure(&block) 141 | @config = Configuration.new 142 | yield(config) 143 | end 144 | 145 | end 146 | 147 | private 148 | 149 | def bot 150 | @bot ||= Bot.new(user_agent) 151 | end 152 | 153 | def client 154 | @client ||= Client.new(user_agent) 155 | end 156 | 157 | def device 158 | @device ||= Device.new(user_agent) 159 | end 160 | 161 | def os 162 | @os ||= OS.new(user_agent) 163 | end 164 | 165 | def android_tablet_fragment? 166 | user_agent =~ build_regex('Android; Tablet;') 167 | end 168 | 169 | def android_mobile_fragment? 170 | user_agent =~ build_regex('Android; Mobile;') 171 | end 172 | 173 | def touch_enabled? 174 | user_agent =~ build_regex('Touch') 175 | end 176 | 177 | def opera_tv_store? 178 | user_agent =~ build_regex('Opera TV Store') 179 | end 180 | 181 | def opera_tablet? 182 | user_agent =~ build_regex('Opera Tablet') 183 | end 184 | 185 | # This is a workaround until we support detecting mobile only browsers 186 | def puffin_browser? 187 | client.name == 'Puffin' 188 | end 189 | 190 | def build_regex(src) 191 | Regexp.new('(?:^|[^A-Z0-9\_\-])(?:' + src + ')', Regexp::IGNORECASE) 192 | end 193 | 194 | end 195 | -------------------------------------------------------------------------------- /spec/fixtures/client/feed_reader.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.21 (KHTML, like Gecko) akregator/4.11.5 Safari/537.21 3 | client: 4 | type: feed reader 5 | name: Akregator 6 | version: "4.11.5" 7 | - 8 | user_agent: Akregator/4.12.3; syndication SUSE 9 | client: 10 | type: feed reader 11 | name: Akregator 12 | version: "4.12.3" 13 | - 14 | user_agent: Akregator/1.2.9; librss/remnants 15 | client: 16 | type: feed reader 17 | name: Akregator 18 | version: "1.2.9" 19 | - 20 | user_agent: Apple-PubSub/65.28 21 | client: 22 | type: feed reader 23 | name: Apple PubSub 24 | version: "65.28" 25 | - 26 | user_agent: FeedDemon/4.5 (http://www.feeddemon.com/; Microsoft Windows) 27 | client: 28 | type: feed reader 29 | name: FeedDemon 30 | version: "4.5" 31 | - 32 | user_agent: FeedDemon/4.5 (http://www.feeddemon.com/; Microsoft Windows XP) 33 | client: 34 | type: feed reader 35 | name: FeedDemon 36 | version: "4.5" 37 | - 38 | user_agent: FeeddlerPro/2.4 CFNetwork/672.0.8 Darwin/14.0.0 39 | client: 40 | type: feed reader 41 | name: Feeddler RSS Reader 42 | version: "2.4" 43 | - 44 | user_agent: FeeddlerRSS/2.4 CFNetwork/548.1.4 Darwin/11.0.0 45 | client: 46 | type: feed reader 47 | name: Feeddler RSS Reader 48 | version: "2.4" 49 | - 50 | user_agent: FeeddlerRSS 2.4 (iPad; iPhone OS 5.1.1; en_US) 51 | client: 52 | type: feed reader 53 | name: Feeddler RSS Reader 54 | version: "2.4" 55 | - 56 | user_agent: JetBrains Omea Reader 2.2 (http://www.jetbrains.com/omea/reader/) 57 | client: 58 | type: feed reader 59 | name: JetBrains Omea Reader 60 | version: "2.2" 61 | - 62 | user_agent: Liferea/1.6.4 (Linux; en_US.UTF-8; http://liferea.sf.net/) 63 | client: 64 | type: feed reader 65 | name: Liferea 66 | version: "1.6.4" 67 | - 68 | user_agent: Liferea/1.10-RC1 (Linux; en_GB.UTF-8; http://liferea.sf.net/) 69 | client: 70 | type: feed reader 71 | name: Liferea 72 | version: "1.10" 73 | - 74 | user_agent: Liferea/1.10.6 (Linux; en_US.UTF8; http://liferea.sf.net/) AppleWebKit (KHTML, like Gecko) 75 | client: 76 | type: feed reader 77 | name: Liferea 78 | version: "1.10.6" 79 | - 80 | user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.74.9 (KHTML, like Gecko) Version/6.0 NetNewsWire/4.0.0 81 | client: 82 | type: feed reader 83 | name: NetNewsWire 84 | version: "4.0.0" 85 | - 86 | user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.74.9 (KHTML, like Gecko) NetNewsWire/3.3.2 87 | client: 88 | type: feed reader 89 | name: NetNewsWire 90 | version: "3.3.2" 91 | - 92 | user_agent: NetNewsWire/4.0.0 (Mac OS X; http://netnewswireapp.com/mac/; gzip-happy) 93 | client: 94 | type: feed reader 95 | name: NetNewsWire 96 | version: "4.0.0" 97 | - 98 | user_agent: newsbeuter/2.7 (Linux x86_64) 99 | client: 100 | type: feed reader 101 | name: Newsbeuter 102 | version: "2.7" 103 | - 104 | user_agent: NewsBlur iPhone App v3.6 105 | client: 106 | type: feed reader 107 | name: NewsBlur Mobile App 108 | version: "3.6" 109 | - 110 | user_agent: NewsBlur iPad App v3.6 111 | client: 112 | type: feed reader 113 | name: NewsBlur Mobile App 114 | version: "3.6" 115 | - 116 | user_agent: NewsBlur/4.0.1 CFNetwork/672.1.13 Darwin/14.0.0 117 | client: 118 | type: feed reader 119 | name: NewsBlur 120 | version: "4.0.1" 121 | - 122 | user_agent: newsbeuter/2.4 (Linux 3.2.0-23-generic; i686; http://www.newsbeuter.org/) libcurl/7.22.0 GnuTLS/2.12.14 zlib/1.2.3.4 libidn/1.23 librtmp/2.3 123 | client: 124 | type: feed reader 125 | name: Newsbeuter 126 | version: "2.4" 127 | - 128 | user_agent: Pulp/1.5.2 (iPad; http://www.acrylicapps.com/pulp/) 129 | client: 130 | type: feed reader 131 | name: Pulp 132 | version: "1.5.2" 133 | - 134 | user_agent: ReadKit/2.4.0 (Mac OS X Version 10.9.2 (Build 13C64)) 135 | client: 136 | type: feed reader 137 | name: ReadKit 138 | version: "2.4.0" 139 | - 140 | user_agent: ReadKit/7017 CFNetwork/673.2.1 Darwin/13.1.0 (x86_64) (MacBookPro10%2C1) 141 | client: 142 | type: feed reader 143 | name: ReadKit 144 | version: "7017" 145 | - 146 | user_agent: Reeder/3.2 CFNetwork/672.1.12 Darwin/14.0.0 147 | client: 148 | type: feed reader 149 | name: Reeder 150 | version: "3.2" 151 | - 152 | user_agent: RssBandit/1.9.0.1002 153 | client: 154 | type: feed reader 155 | name: RSS Bandit 156 | version: "1.9.0.1002" 157 | - 158 | user_agent: RssBandit/1.9.0.1002 (.NET CLR 2.0.50727.7512; WinNT 6.2.9200.0; http://www.rssbandit.org) 159 | client: 160 | type: feed reader 161 | name: RSS Bandit 162 | version: "1.9.0.1002" 163 | - 164 | user_agent: RSS Junkie Daemon 165 | client: 166 | type: feed reader 167 | name: RSS Junkie 168 | version: 169 | - 170 | user_agent: RSSOwl/2.2.1.201312301314 (Windows; U; en) 171 | client: 172 | type: feed reader 173 | name: RSSOwl 174 | version: "2.2.1.201312301314" 175 | - 176 | user_agent: RSSOwl/2.2.1.201312301316 (X11; U; en) 177 | client: 178 | type: feed reader 179 | name: RSSOwl 180 | version: "2.2.1.201312301316" 181 | 182 | - 183 | user_agent: Stringer (https://github.com/swanson/stringer) 184 | client: 185 | type: feed reader 186 | name: Stringer 187 | version: "" -------------------------------------------------------------------------------- /lib/device_detector/os.rb: -------------------------------------------------------------------------------- 1 | require 'set' 2 | 3 | class DeviceDetector 4 | class OS < Parser 5 | 6 | def name 7 | os_info[:name] 8 | end 9 | 10 | def short_name 11 | os_info[:short] 12 | end 13 | 14 | def family 15 | os_info[:family] 16 | end 17 | 18 | def desktop? 19 | DESKTOP_OSS.include?(family) 20 | end 21 | 22 | def full_version 23 | raw_version = super.to_s.split('_').join('.') 24 | raw_version == '' ? nil : raw_version 25 | end 26 | 27 | private 28 | 29 | def os_info 30 | from_cache(['os_info', self.class.name, user_agent]) do 31 | os_name = NameExtractor.new(user_agent, regex_meta).call 32 | if os_name && short = DOWNCASED_OPERATING_SYSTEMS[os_name.downcase] 33 | os_name = OPERATING_SYSTEMS[short] 34 | else 35 | short = 'UNK' 36 | end 37 | { name: os_name, short: short, family: FAMILY_TO_OS[short] } 38 | end 39 | end 40 | 41 | DESKTOP_OSS = Set.new(['AmigaOS', 'IBM', 'GNU/Linux', 'Mac', 'Unix', 'Windows', 'BeOS', 'Chrome OS']) 42 | 43 | # OS short codes mapped to long names 44 | OPERATING_SYSTEMS = { 45 | 'AIX' => 'AIX', 46 | 'AND' => 'Android', 47 | 'AMG' => 'AmigaOS', 48 | 'ATV' => 'Apple TV', 49 | 'ARL' => 'Arch Linux', 50 | 'BTR' => 'BackTrack', 51 | 'SBA' => 'Bada', 52 | 'BEO' => 'BeOS', 53 | 'BLB' => 'BlackBerry OS', 54 | 'QNX' => 'BlackBerry Tablet OS', 55 | 'BMP' => 'Brew', 56 | 'CES' => 'CentOS', 57 | 'COS' => 'Chrome OS', 58 | 'CYN' => 'CyanogenMod', 59 | 'DEB' => 'Debian', 60 | 'DFB' => 'DragonFly', 61 | 'FED' => 'Fedora', 62 | 'FOS' => 'Firefox OS', 63 | 'BSD' => 'FreeBSD', 64 | 'GNT' => 'Gentoo', 65 | 'GTV' => 'Google TV', 66 | 'HPX' => 'HP-UX', 67 | 'HAI' => 'Haiku OS', 68 | 'IRI' => 'IRIX', 69 | 'INF' => 'Inferno', 70 | 'KNO' => 'Knoppix', 71 | 'KBT' => 'Kubuntu', 72 | 'LIN' => 'GNU/Linux', 73 | 'LBT' => 'Lubuntu', 74 | 'VLN' => 'VectorLinux', 75 | 'MAC' => 'Mac', 76 | 'MAE' => 'Maemo', 77 | 'MDR' => 'Mandriva', 78 | 'SMG' => 'MeeGo', 79 | 'MCD' => 'MocorDroid', 80 | 'MIN' => 'Mint', 81 | 'MLD' => 'MildWild', 82 | 'MOR' => 'MorphOS', 83 | 'NBS' => 'NetBSD', 84 | 'MTK' => 'MTK / Nucleus', 85 | 'WII' => 'Nintendo', 86 | 'NDS' => 'Nintendo Mobile', 87 | 'OS2' => 'OS/2', 88 | 'T64' => 'OSF1', 89 | 'OBS' => 'OpenBSD', 90 | 'PSP' => 'PlayStation Portable', 91 | 'PS3' => 'PlayStation', 92 | 'RHT' => 'Red Hat', 93 | 'ROS' => 'RISC OS', 94 | 'REM' => 'Remix OS', 95 | 'RZD' => 'RazoDroiD', 96 | 'SAB' => 'Sabayon', 97 | 'SSE' => 'SUSE', 98 | 'SAF' => 'Sailfish OS', 99 | 'SLW' => 'Slackware', 100 | 'SOS' => 'Solaris', 101 | 'SYL' => 'Syllable', 102 | 'SYM' => 'Symbian', 103 | 'SYS' => 'Symbian OS', 104 | 'S40' => 'Symbian OS Series 40', 105 | 'S60' => 'Symbian OS Series 60', 106 | 'SY3' => 'Symbian^3', 107 | 'TDX' => 'ThreadX', 108 | 'TIZ' => 'Tizen', 109 | 'UBT' => 'Ubuntu', 110 | 'WTV' => 'WebTV', 111 | 'WIN' => 'Windows', 112 | 'WCE' => 'Windows CE', 113 | 'WMO' => 'Windows Mobile', 114 | 'WPH' => 'Windows Phone', 115 | 'WRT' => 'Windows RT', 116 | 'XBX' => 'Xbox', 117 | 'XBT' => 'Xubuntu', 118 | 'YNS' => 'YunOs', 119 | 'IOS' => 'iOS', 120 | 'POS' => 'palmOS', 121 | 'WOS' => 'webOS' 122 | } 123 | 124 | DOWNCASED_OPERATING_SYSTEMS = OPERATING_SYSTEMS.each_with_object({}){|(short,long),h| h[long.downcase] = short} 125 | 126 | OS_FAMILIES = { 127 | 'Android' => ['AND', 'CYN', 'REM', 'RZD', 'MLD', 'MCD', 'YNS'], 128 | 'AmigaOS' => ['AMG', 'MOR'], 129 | 'Apple TV' => ['ATV'], 130 | 'BlackBerry' => ['BLB', 'QNX'], 131 | 'Brew' => ['BMP'], 132 | 'BeOS' => ['BEO', 'HAI'], 133 | 'Chrome OS' => ['COS'], 134 | 'Firefox OS' => ['FOS'], 135 | 'Gaming Console' => ['WII', 'PS3'], 136 | 'Google TV' => ['GTV'], 137 | 'IBM' => ['OS2'], 138 | 'iOS' => ['IOS'], 139 | 'RISC OS' => ['ROS'], 140 | 'GNU/Linux' => ['LIN', 'ARL', 'DEB', 'KNO', 'MIN', 'UBT', 'KBT', 'XBT', 'LBT', 'FED', 'RHT', 'VLN', 'MDR', 'GNT', 'SAB', 'SLW', 'SSE', 'CES', 'BTR', 'SAF'], 141 | 'Mac' => ['MAC'], 142 | 'Mobile Gaming Console' => ['PSP', 'NDS', 'XBX'], 143 | 'Real-time OS' => ['MTK', 'TDX'], 144 | 'Other Mobile' => ['WOS', 'POS', 'SBA', 'TIZ', 'SMG', 'MAE'], 145 | 'Symbian' => ['SYM', 'SYS', 'SY3', 'S60', 'S40'], 146 | 'Unix' => ['SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64', 'INF'], 147 | 'WebTV' => ['WTV'], 148 | 'Windows' => ['WIN'], 149 | 'Windows Mobile' => ['WPH', 'WMO', 'WCE', 'WRT'] 150 | } 151 | 152 | FAMILY_TO_OS = OS_FAMILIES.each_with_object({}) do |(family,oss),h| 153 | oss.each{|os| h[os] = family} 154 | end 155 | 156 | def filenames 157 | ['oss.yml'] 158 | end 159 | 160 | end 161 | 162 | end 163 | -------------------------------------------------------------------------------- /regexes/device/televisions.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | # 7 | # ATTENTION: This file may only include tv user agents that contain 'HbbTV/([1-9]{1}(\.[0-9]{1}){1,2})' 8 | # 9 | ############### 10 | 11 | # Airties 12 | Airties: 13 | regex: 'Airties' 14 | device: 'tv' 15 | models: 16 | - regex: 'Airties; ?([^);/]+)' 17 | model: '$1' 18 | 19 | # Altech UEC 20 | 'Altech UEC': 21 | regex: 'Altech UEC' 22 | device: 'tv' 23 | models: 24 | - regex: 'Altech UEC; ?([^);/]+)' 25 | model: '$1' 26 | 27 | # BangOlufsen 28 | BangOlufsen: 29 | regex: 'Bangolufsen' 30 | device: 'tv' 31 | model: 'BeoVision' 32 | 33 | # Changhong 34 | Changhong: 35 | regex: 'Changhong' 36 | device: 'tv' 37 | models: 38 | - regex: 'Changhong; ?([^);/]+)' 39 | model: '$1' 40 | 41 | # CreNova 42 | CreNova: 43 | regex: 'CreNova' 44 | device: 'tv' 45 | model: 'CNV001' 46 | 47 | # DMM 48 | DMM: 49 | regex: 'DMM' 50 | device: 'tv' 51 | model: 'Dreambox' 52 | 53 | # Grundig 54 | Grundig: 55 | regex: '(OWB|Grundig|Arcelik)' 56 | device: 'tv' 57 | model: '' 58 | 59 | # Humax 60 | Humax: 61 | regex: 'Humax' 62 | device: 'tv' 63 | models: 64 | - regex: '(HD-FOX C|HD (FOX\+|NANO)|iCord (HD\+|MINI|Cable)|(CX|IR)HD-5100(C|S)|HM9503HD)' 65 | model: '$1' 66 | - regex: 'HMS1000S' 67 | model: 'HMS-1000S' 68 | - regex: 'Humax; ([^);/]+)' 69 | model: '$1' 70 | 71 | # IKEA 72 | Ikea: 73 | regex: 'Ikea' 74 | device: 'tv' 75 | models: 76 | - regex: '(LF1V[0-9]{3})' 77 | model: '$1' 78 | 79 | # Intek 80 | Intek: 81 | regex: 'Intek' 82 | device: 'tv' 83 | models: 84 | - regex: '(Vantage|VT-100|VT-1)' 85 | model: '$1' 86 | 87 | # Inverto 88 | Inverto: 89 | regex: 'Inverto' 90 | device: 'tv' 91 | models: 92 | - regex: 'inverto; ([^);/]+)' 93 | model: '$1' 94 | - regex: '(Volksbox Web Edition|Volksbox Essential|Volksbox II|Volksbox)' 95 | model: '$1' 96 | 97 | # LG 98 | LG: 99 | regex: 'LGE' 100 | device: 'tv' 101 | models: 102 | - regex: '(NetCast [0-9]{1}.[0-9]{1}|GLOBAL_PLAT3)' 103 | model: '$1' 104 | 105 | # Loewe 106 | Loewe: 107 | regex: 'Loewe' 108 | device: 'tv' 109 | models: 110 | - regex: '([A-Z]{2}[0-9]{3})' 111 | model: '$1' 112 | 113 | # MediaTek 114 | MediaTek: 115 | regex: 'MTK' 116 | device: 'tv' 117 | models: 118 | - regex: '(MT[0-9]{4})' 119 | model: '$1' 120 | 121 | # Medion 122 | Medion: 123 | regex: 'Medion' 124 | device: 'tv' 125 | models: 126 | - regex: '(MB[0-9]{2})' 127 | model: '$1' 128 | 129 | # Metz 130 | Metz: 131 | regex: 'Metz' 132 | device: 'tv' 133 | model: '' 134 | 135 | # Panasonic 136 | Panasonic: 137 | regex: 'Panasonic' 138 | device: 'tv' 139 | models: 140 | - regex: '(VIERA [0-9]{1,4})|(DIGA [A-Z]{1}[0-9]{4})' 141 | model: '$1' 142 | - regex: 'DIGA Webkit ([A-Z]{1}[0-9]{4})' 143 | model: 'DIGA $1' 144 | 145 | # PEAQ 146 | PEAQ: 147 | regex: 'PEAQ' 148 | device: 'tv' 149 | models: 150 | - regex: '(LF1V[0-9]{3})' 151 | model: '$1' 152 | 153 | # Philips 154 | Philips: 155 | regex: 'Philips|NETTV/' 156 | device: 'tv' 157 | models: 158 | - regex: 'Philips[,;] ?((?! )[^),;/]+)' 159 | model: '$1' 160 | - regex: 'NETTV/[0-9\.]{5}' 161 | model: 'NetTV Series' 162 | 163 | # Samsung 164 | Samsung: 165 | regex: 'Samsung|Maple_2011' 166 | device: 'tv' 167 | models: 168 | - regex: 'SmartTV(2012|2013|2014|2015)' 169 | model: 'Smart TV $1' 170 | - regex: 'Maple_2011' 171 | model: 'Smart TV 2011' 172 | 173 | # Selevision 174 | Selevision: 175 | regex: 'Selevision' 176 | device: 'tv' 177 | models: 178 | - regex: 'Selevision; (?:Selevision )?([^);/]+)' 179 | model: '$1' 180 | - regex: '(EMC1000i)' 181 | model: '$1' 182 | 183 | # Sharp 184 | Sharp: 185 | regex: 'Sharp' 186 | device: 'tv' 187 | models: 188 | - regex: 'Sharp[,;] ?((?! |HbbTV)[^),;/]+)' 189 | model: '$1' 190 | - regex: '(LE[0-9]{3}[A-Z]{0,3})' 191 | model: '$1' 192 | 193 | # Skyworth 194 | Skyworth: 195 | regex: 'Sky_worth' 196 | device: 'tv' 197 | models: 198 | - regex: 'Sky_worth;([^);/]+)' 199 | model: '$1' 200 | 201 | # Smart 202 | Smart: 203 | regex: 'Smart[^a-z]' 204 | device: 'tv' 205 | models: 206 | - regex: 'Smart; ([^);/]+)' 207 | model: '$1' 208 | - regex: '([A-Z]{2}[0-9]{2}|ZAPPIX)' 209 | model: '$1' 210 | 211 | # Sony 212 | Sony: 213 | regex: 'Sony' 214 | device: 'tv' 215 | models: 216 | - regex: '(KDL[0-9]{2}[A-Z]{1,2}[0-9]{3})' 217 | model: '$1' 218 | 219 | # TechniSat 220 | TechniSat: 221 | regex: 'TechniSat' 222 | device: 'tv' 223 | models: 224 | - regex: '((DigiCorder|MultyVision|Digit) (ISIO S|ISIO C|ISIO))' 225 | model: '$1' 226 | 227 | # TechnoTrend 228 | TechnoTrend: 229 | regex: 'TechnoTrend' 230 | device: 'tv' 231 | models: 232 | - regex: '([A-Z]{1}-[0-9]{3})' 233 | model: '$1' 234 | 235 | # Telefunken 236 | Telefunken: 237 | regex: 'Telefunken' 238 | device: 'tv' 239 | models: 240 | - regex: '(MB[0-9]{2})' 241 | model: '$1' 242 | # TCL 243 | TCL: 244 | regex: 'TCL' 245 | device: 'tv' 246 | models: 247 | - regex: '(LF1V[0-9]{3})' 248 | model: '$1' 249 | 250 | # Thomson 251 | Thomson: 252 | regex: 'THOMSON|THOM' 253 | device: 'tv' 254 | models: 255 | - regex: '(LF1V[0-9]{3})' 256 | model: '$1' 257 | 258 | # Toshiba 259 | Toshiba: 260 | regex: 'Toshiba' 261 | device: 'tv' 262 | models: 263 | - regex: '(([0-9]{2}|DTV_)[A-Z]{2}[0-9]{1,3})' 264 | model: '$1' 265 | 266 | # Vestel 267 | Vestel: 268 | regex: 'Vestel' 269 | device: 'tv' 270 | models: 271 | - regex: '(MB[0-9]{2})' 272 | model: '$1' 273 | 274 | # Videoweb 275 | Videoweb: 276 | regex: 'videoweb|tv2n' 277 | device: 'tv' 278 | models: 279 | - regex: '(tv2n)' 280 | model: '$1' 281 | - regex: '(videowebtv)' 282 | model: 'VideoWeb TV' 283 | -------------------------------------------------------------------------------- /spec/fixtures/detector/console.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | user_agent: Mozilla/5.0 (Linux; Android 4.1.1; ARCHOS GAMEPAD Build/JRO03H) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19 4 | os: 5 | name: Android 6 | short_name: AND 7 | version: "4.1.1" 8 | platform: 9 | client: 10 | type: browser 11 | name: Chrome 12 | short_name: CH 13 | version: "18.0.1025.166" 14 | engine: WebKit 15 | device: 16 | type: console 17 | brand: AR 18 | model: Gamepad 19 | os_family: Android 20 | browser_family: Chrome 21 | - 22 | user_agent: Mozilla/5.0 (Linux; U; Android 4.2.2; fr-fr; ARCHOS GAMEPAD2 Build/JDQ39) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 23 | os: 24 | name: Android 25 | short_name: AND 26 | version: "4.2.2" 27 | platform: 28 | client: 29 | type: browser 30 | name: Android Browser 31 | short_name: AN 32 | version: 33 | engine: WebKit 34 | device: 35 | type: console 36 | brand: AR 37 | model: Gamepad 2 38 | os_family: Android 39 | browser_family: Android Browser 40 | - 41 | user_agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox) 42 | os: 43 | name: Windows 44 | short_name: WIN 45 | version: "7" 46 | platform: 47 | client: 48 | type: browser 49 | name: Internet Explorer 50 | short_name: IE 51 | version: "9.0" 52 | engine: Trident 53 | device: 54 | type: console 55 | brand: MS 56 | model: Xbox 360 57 | os_family: Windows 58 | browser_family: Internet Explorer 59 | - 60 | user_agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Xbox; Xbox One) 61 | os: 62 | name: Windows 63 | short_name: WIN 64 | version: "8" 65 | platform: 66 | client: 67 | type: browser 68 | name: Internet Explorer 69 | short_name: IE 70 | version: "10.0" 71 | engine: Trident 72 | device: 73 | type: console 74 | brand: MS 75 | model: Xbox One 76 | os_family: Windows 77 | browser_family: Internet Explorer 78 | - 79 | user_agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; Xbox; Xbox One) 80 | os: 81 | name: Windows Phone 82 | short_name: WPH 83 | version: "8.0" 84 | platform: 85 | client: 86 | type: browser 87 | name: IE Mobile 88 | short_name: IM 89 | version: "10.0" 90 | engine: Trident 91 | device: 92 | type: console 93 | brand: MS 94 | model: Xbox One 95 | os_family: Windows Mobile 96 | browser_family: Internet Explorer 97 | - 98 | user_agent: Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7498.EU 99 | os: 100 | name: Nintendo Mobile 101 | short_name: NDS 102 | version: "3DS" 103 | platform: 104 | client: 105 | type: browser 106 | name: NetFront 107 | short_name: NF 108 | version: 109 | engine: 110 | device: 111 | type: console 112 | brand: NI 113 | model: 3DS 114 | os_family: Mobile Gaming Console 115 | browser_family: NetFront 116 | - 117 | user_agent: Bunjalloo/0.7.6(Nintendo DS;U;en) 118 | os: 119 | name: Nintendo Mobile 120 | short_name: NDS 121 | version: "DS" 122 | platform: 123 | client: 124 | type: browser 125 | name: Bunjalloo 126 | short_name: BJ 127 | version: "0.7.6" 128 | engine: 129 | device: 130 | type: console 131 | brand: NI 132 | model: DS 133 | os_family: Mobile Gaming Console 134 | browser_family: Unknown 135 | - 136 | user_agent: Opera/9.30 (Nintendo Wii; U; ; 3642; en) 137 | os: 138 | name: Nintendo 139 | short_name: WII 140 | version: "Wii" 141 | platform: 142 | client: 143 | type: browser 144 | name: Opera 145 | short_name: OP 146 | version: "9.30" 147 | engine: Presto 148 | device: 149 | type: console 150 | brand: NI 151 | model: Wii 152 | os_family: Gaming Console 153 | browser_family: Opera 154 | - 155 | user_agent: Mozilla/5.0 (Nintendo WiiU) AppleWebKit/534.52 (KHTML, like Gecko) NX/2.1.0.8.21 NintendoBrowser/1.0.0.7494.US 156 | os: 157 | name: Nintendo 158 | short_name: WII 159 | version: "Wii" 160 | platform: 161 | client: 162 | type: browser 163 | name: NetFront 164 | short_name: NF 165 | version: 166 | engine: WebKit 167 | device: 168 | type: console 169 | brand: NI 170 | model: WiiU 171 | os_family: Gaming Console 172 | browser_family: NetFront 173 | - 174 | user_agent: Mozilla/5.0 (Linux; U; Android OUYA 4.1.2; en-us; OUYA Build/JZO54L-OUYA) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 175 | os: 176 | name: Android 177 | short_name: AND 178 | version: "4.1.2" 179 | platform: 180 | client: 181 | type: browser 182 | name: Android Browser 183 | short_name: AN 184 | version: 185 | engine: WebKit 186 | device: 187 | type: console 188 | brand: OU 189 | model: OUYA 190 | os_family: Android 191 | browser_family: Android Browser 192 | - 193 | user_agent: Mozilla/5.0 (PLAYSTATION 3 4.46) AppleWebKit/531.22.8 (KHTML, like Gecko) 194 | os: 195 | name: PlayStation 196 | short_name: PS3 197 | version: "3" 198 | platform: 199 | client: 200 | type: browser 201 | name: NetFront 202 | short_name: NF 203 | version: 204 | engine: WebKit 205 | device: 206 | type: console 207 | brand: SO 208 | model: PlayStation 3 209 | os_family: Gaming Console 210 | browser_family: NetFront 211 | - 212 | user_agent: Mozilla/5.0 (PlayStation 4 1.52) AppleWebKit/536.26 (KHTML, like Gecko) 213 | os: 214 | name: PlayStation 215 | short_name: PS3 216 | version: "4" 217 | platform: 218 | client: 219 | type: browser 220 | name: NetFront 221 | short_name: NF 222 | version: 223 | engine: WebKit 224 | device: 225 | type: console 226 | brand: SO 227 | model: PlayStation 4 228 | os_family: Gaming Console 229 | browser_family: NetFront 230 | - 231 | user_agent: Mozilla/4.0 (PlayStation Portable); 2.00) 232 | os: 233 | name: PlayStation Portable 234 | short_name: PSP 235 | version: "Portable" 236 | platform: 237 | client: 238 | type: browser 239 | name: NetFront 240 | short_name: NF 241 | version: 242 | engine: 243 | device: 244 | type: console 245 | brand: SO 246 | model: PlayStation Portable 247 | os_family: Mobile Gaming Console 248 | browser_family: NetFront 249 | - 250 | user_agent: Mozilla/5.0 (PlayStation Vita 3.01) AppleWebKit/536.26 (KHTML, like Gecko) Silk/3.2 251 | os: 252 | name: PlayStation Portable 253 | short_name: PSP 254 | version: "Vita" 255 | platform: 256 | client: 257 | type: browser 258 | name: Mobile Silk 259 | short_name: MS 260 | version: "3.2" 261 | engine: Blink 262 | device: 263 | type: console 264 | brand: SO 265 | model: PlayStation Vita 266 | os_family: Mobile Gaming Console 267 | browser_family: Unknown 268 | -------------------------------------------------------------------------------- /spec/fixtures/detector/tablet-2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | user_agent: Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; TAB09-410 Build/Noble TAB09-410) AppleWebKit/534.30 (KHTML, like Gecko)Version/4.0 Safari/534.30 4 | os: 5 | name: Android 6 | short_name: AND 7 | version: "4.2.2" 8 | platform: 9 | client: 10 | type: browser 11 | name: Android Browser 12 | short_name: AN 13 | version: 14 | engine: WebKit 15 | device: 16 | type: tablet 17 | brand: YA 18 | model: Noble 9.7 19 | os_family: Android 20 | browser_family: Android Browser 21 | - 22 | user_agent: Mozilla/5.0 (Linux; Android 4.2.2; Noble TAB07-485 Build/Noble TAB07-485) AppleWebKit/537.36 (KHTML like Gecko) Chrome/32.0.1700.99 Safari/537.36 23 | os: 24 | name: Android 25 | short_name: AND 26 | version: "4.2.2" 27 | platform: 28 | client: 29 | type: browser 30 | name: Chrome 31 | short_name: CH 32 | version: "32.0.1700.99" 33 | engine: Blink 34 | device: 35 | type: tablet 36 | brand: YA 37 | model: Noble Mini 38 | os_family: Android 39 | browser_family: Chrome 40 | - 41 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; TAB10-201 Build/Xenta) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 42 | os: 43 | name: Android 44 | short_name: AND 45 | version: "4.1.1" 46 | platform: 47 | client: 48 | type: browser 49 | name: Android Browser 50 | short_name: AN 51 | version: 52 | engine: WebKit 53 | device: 54 | type: tablet 55 | brand: YA 56 | model: Xenta 10ic 57 | os_family: Android 58 | browser_family: Android Browser 59 | - 60 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; fr-fr; Xenta TAB10-211 Build/Xenta TAB10-211) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 61 | os: 62 | name: Android 63 | short_name: AND 64 | version: "4.1.1" 65 | platform: 66 | client: 67 | type: browser 68 | name: Android Browser 69 | short_name: AN 70 | version: 71 | engine: WebKit 72 | device: 73 | type: tablet 74 | brand: YA 75 | model: Xenta 10ic 76 | os_family: Android 77 | browser_family: Android Browser 78 | - 79 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Xenta TAB13-201 Build/Xenta TAB13-201) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 80 | os: 81 | name: Android 82 | short_name: AND 83 | version: "4.1.1" 84 | platform: 85 | client: 86 | type: browser 87 | name: Android Browser 88 | short_name: AN 89 | version: 90 | engine: WebKit 91 | device: 92 | type: tablet 93 | brand: YA 94 | model: Xenta 13c 95 | os_family: Android 96 | browser_family: Android Browser 97 | - 98 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; fr-be; Xenta-TAB07-210 Build/Xenta-TAB07-210) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 99 | os: 100 | name: Android 101 | short_name: AND 102 | version: "4.1.1" 103 | platform: 104 | client: 105 | type: browser 106 | name: Android Browser 107 | short_name: AN 108 | version: 109 | engine: WebKit 110 | device: 111 | type: tablet 112 | brand: YA 113 | model: Xenta 7c 114 | os_family: Android 115 | browser_family: Android Browser 116 | - 117 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; nl-be; Xenta-TAB07-211 Build/Xenta-TAB07-211) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 118 | os: 119 | name: Android 120 | short_name: AND 121 | version: "4.1.1" 122 | platform: 123 | client: 124 | type: browser 125 | name: Android Browser 126 | short_name: AN 127 | version: 128 | engine: WebKit 129 | device: 130 | type: tablet 131 | brand: YA 132 | model: Xenta 7c 133 | os_family: Android 134 | browser_family: Android Browser 135 | - 136 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; TAB07-200 Build/Xenta) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 137 | os: 138 | name: Android 139 | short_name: AND 140 | version: "4.1.1" 141 | platform: 142 | client: 143 | type: browser 144 | name: Android Browser 145 | short_name: AN 146 | version: 147 | engine: WebKit 148 | device: 149 | type: tablet 150 | brand: YA 151 | model: Xenta 7ic 152 | os_family: Android 153 | browser_family: Android Browser 154 | - 155 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.2; fr-fr; Xenta TAB08-201-3G Build/Xenta TAB08-201-3G) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 156 | os: 157 | name: Android 158 | short_name: AND 159 | version: "4.1.2" 160 | platform: 161 | client: 162 | type: browser 163 | name: Android Browser 164 | short_name: AN 165 | version: 166 | engine: WebKit 167 | device: 168 | type: tablet 169 | brand: YA 170 | model: Xenta 8c 171 | os_family: Android 172 | browser_family: Android Browser 173 | - 174 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; fr-be; Xenta TAB08-200 Build/Xenta TAB08-200) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 175 | os: 176 | name: Android 177 | short_name: AND 178 | version: "4.1.1" 179 | platform: 180 | client: 181 | type: browser 182 | name: Android Browser 183 | short_name: AN 184 | version: 185 | engine: WebKit 186 | device: 187 | type: tablet 188 | brand: YA 189 | model: Xenta 8ic 190 | os_family: Android 191 | browser_family: Android Browser 192 | - 193 | user_agent: Mozilla/5.0 (Linux; U; Android 4.0.4; es-es; Xenta TAB9-200 Build/Xenta TAB9-200) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 194 | os: 195 | name: Android 196 | short_name: AND 197 | version: "4.0.4" 198 | platform: 199 | client: 200 | type: browser 201 | name: Android Browser 202 | short_name: AN 203 | version: 204 | engine: WebKit 205 | device: 206 | type: tablet 207 | brand: YA 208 | model: Xenta 9.7ic 209 | os_family: Android 210 | browser_family: Android Browser 211 | - 212 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; bg-bg; Xenta TAB09-211 Build/XentaTAB09-211) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Safari/534.30 213 | os: 214 | name: Android 215 | short_name: AND 216 | version: "4.1.1" 217 | platform: 218 | client: 219 | type: browser 220 | name: Android Browser 221 | short_name: AN 222 | version: 223 | engine: WebKit 224 | device: 225 | type: tablet 226 | brand: YA 227 | model: Xenta 9.7ic+ 228 | os_family: Android 229 | browser_family: Android Browser 230 | - 231 | user_agent: Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; N101 DUAL CORE2 V11 Build/JRO03H) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30 232 | os: 233 | name: Android 234 | short_name: AND 235 | version: "4.1.1" 236 | platform: 237 | client: 238 | type: browser 239 | name: Android Browser 240 | short_name: AN 241 | version: 242 | engine: WebKit 243 | device: 244 | type: tablet 245 | brand: YU 246 | model: N101 247 | os_family: Android 248 | browser_family: Android Browser 249 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Podigee 2 | 3 | GNU LESSER GENERAL PUBLIC LICENSE 4 | 5 | Version 3, 29 June 2007 6 | 7 | Copyright © 2007 Free Software Foundation, Inc. 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 10 | 11 | This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. 15 | 16 | “The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. 17 | 18 | An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. 19 | 20 | A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. 21 | 22 | The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. 23 | 24 | The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 25 | 26 | 1. Exception to Section 3 of the GNU GPL. 27 | You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 28 | 29 | 2. Conveying Modified Versions. 30 | If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: 31 | 32 | a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or 33 | b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 34 | 3. Object Code Incorporating Material from Library Header Files. 35 | The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: 36 | 37 | a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. 38 | b) Accompany the object code with a copy of the GNU GPL and this license document. 39 | 4. Combined Works. 40 | You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: 41 | 42 | a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. 43 | b) Accompany the Combined Work with a copy of the GNU GPL and this license document. 44 | c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. 45 | d) Do one of the following: 46 | 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 47 | 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. 48 | e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 49 | 5. Combined Libraries. 50 | You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: 51 | 52 | a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. 53 | b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 54 | 6. Revised Versions of the GNU Lesser General Public License. 55 | The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 56 | 57 | Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. 58 | 59 | If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. 60 | 61 | -------------------------------------------------------------------------------- /spec/fixtures/parser/vendorfragments.yml: -------------------------------------------------------------------------------- 1 | - 2 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; Media Center PC 6.0; MAAR; Tablet PC 2.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E) 3 | vendor: AC 4 | - 5 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; Touch; MAARJS) 6 | vendor: AC 7 | - 8 | useragent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; MAAU; rv:11.0) like Gecko 9 | vendor: AU 10 | - 11 | useragent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; ASU2JS; rv:11.0) like Gecko 12 | vendor: AU 13 | - 14 | useragent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; NP06; rv:11.0) like Gecko 15 | vendor: AU 16 | - 17 | useragent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; ASJB; rv:11.0) like Gecko 18 | vendor: AU 19 | - 20 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; CPDTDF; .NET4.0C; InfoPath.3; .NET4.0E; Microsoft Outlook 14.0.7113; ms-office; MSOffice 14) 21 | vendor: CQ 22 | - 23 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; CPNTDFJS) 24 | vendor: CQ 25 | - 26 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; CMNTDF; InfoPath.2; .NET4.0C; .NET4.0E) 27 | vendor: CQ 28 | - 29 | user_agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; CMDTDFJS; Tablet PC 2.0) 30 | vendor: CQ 31 | - 32 | user_agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; CMDTDF; InfoPath.3) 33 | vendor: CQ 34 | - 35 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/4.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDC; .NET4.0C; .NET4.0E) 36 | vendor: DL 37 | - 38 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch; MDDCJS) 39 | vendor: DL 40 | - 41 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; GTB7.5; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDR) 42 | vendor: DL 43 | - 44 | useragent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MDDRJS) 45 | vendor: DL 46 | - 47 | useragent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; MDDSJS; rv:11.0) like Gecko 48 | vendor: DL 49 | - 50 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; McAfee; MDDSJS) 51 | vendor: DL 52 | - 53 | useragent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; FSJB; rv:11.0) like Gecko 54 | vendor: FU 55 | - 56 | useragent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MAFSJS) 57 | vendor: FU 58 | - 59 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; MAFS; InfoPath.2; OfficeLiveConnector.1.5; OfficeLivePatch.1.3; MSOffice 12) 60 | vendor: FU 61 | - 62 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MAGW; .NET4.0C; .NET4.0E; Microsoft Outlook 14.0.7113; ms-office; MSOffice 14) 63 | vendor: GA 64 | - 65 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MAGWJS) 66 | vendor: GA 67 | - 68 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; HPCMHP) 69 | vendor: HP 70 | - 71 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; HPDTDFJS) 72 | vendor: HP 73 | - 74 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; HPNTDFJS) 75 | vendor: HP 76 | - 77 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MANM; .NET4.0C; InfoPath.3; .NET4.0E) 78 | vendor: HY 79 | - 80 | useragent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; MANMJS; rv:11.0) like Gecko 81 | vendor: HY 82 | - 83 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/4.0; QQDownload 691; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MALC) 84 | vendor: LE 85 | - 86 | useragent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; LEN2) 87 | vendor: LE 88 | - 89 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; MALEJS) 90 | vendor: LE 91 | - 92 | useragent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; LCJB; rv:11.0) like Gecko 93 | vendor: LE 94 | - 95 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Touch; MALCJS; WebView/1.0) 96 | vendor: LE 97 | - 98 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch; MALNJS) 99 | vendor: LE 100 | - 101 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; MALN) 102 | vendor: LE 103 | - 104 | useragent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; MAMD) 105 | vendor: MD 106 | - 107 | useragent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; MAM3; InfoPath.3; .NET4.0E; MAM3) 108 | vendor: MZ 109 | - 110 | useragent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; MAMI; rv:11.0) like Gecko 111 | vendor: MZ 112 | - 113 | useragent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; MAMIJS; rv:11.0) like Gecko 114 | vendor: MZ 115 | - 116 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MASM; .NET4.0C; .NET4.0E) 117 | vendor: SA 118 | - 119 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MASMJS) 120 | vendor: SA 121 | - 122 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; SMJB) 123 | vendor: SA 124 | - 125 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0; MASP) 126 | vendor: SO 127 | - 128 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; Media Center PC 6.0; MASA) 129 | vendor: SO 130 | - 131 | useragent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; Media Center PC 6.0; MASE) 132 | vendor: SO 133 | - 134 | useragent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; Trident/7.0; MASAJS; rv:11.0) like Gecko 135 | vendor: SO 136 | - 137 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; Touch; MASPJS) 138 | vendor: SO 139 | - 140 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0; MASEJS) 141 | vendor: SO 142 | - 143 | useragent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0; MATMJS) 144 | vendor: TS 145 | - 146 | useragent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/7.0; MATM) 147 | vendor: TS 148 | - 149 | useragent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/7.0; MATP) 150 | vendor: TS 151 | - 152 | useragent: Mozilla/5.0 (MSIE 9.0; Windows NT 6.3; WOW64; Trident/7.0; MATBJS; rv:11.0) like Gecko 153 | vendor: TS 154 | - 155 | useragent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; MATPJS; rv:11.0) like Gecko 156 | vendor: TS 157 | - 158 | useragent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; TNJB; rv:11.0) like Gecko 159 | vendor: TS 160 | - 161 | useragent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; Trident/7.0; Touch; TAJB; rv:11.0) like Gecko 162 | vendor: TS 163 | -------------------------------------------------------------------------------- /spec/fixtures/detector/feed_reader.yml: -------------------------------------------------------------------------------- 1 | - 2 | user_agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.21 (KHTML, like Gecko) akregator/4.11.5 Safari/537.21 3 | os: 4 | name: GNU/Linux 5 | short_name: LIN 6 | version: 7 | platform: x64 8 | client: 9 | type: feed reader 10 | name: Akregator 11 | version: "4.11.5" 12 | device: 13 | type: desktop 14 | brand: 15 | model: 16 | os_family: GNU/Linux 17 | browser_family: Unknown 18 | - 19 | user_agent: Akregator/4.12.3; syndication SUSE 20 | os: 21 | name: SUSE 22 | short_name: SSE 23 | version: 24 | platform: 25 | client: 26 | type: feed reader 27 | name: Akregator 28 | version: "4.12.3" 29 | device: 30 | type: desktop 31 | brand: 32 | model: 33 | os_family: GNU/Linux 34 | browser_family: Unknown 35 | - 36 | user_agent: Akregator/1.2.9; librss/remnants 37 | os: [ ] 38 | client: 39 | type: feed reader 40 | name: Akregator 41 | version: "1.2.9" 42 | device: 43 | type: 44 | brand: 45 | model: 46 | os_family: Unknown 47 | browser_family: Unknown 48 | - 49 | user_agent: Apple-PubSub/65.28 50 | os: [ ] 51 | client: 52 | type: feed reader 53 | name: Apple PubSub 54 | version: "65.28" 55 | device: 56 | type: 57 | brand: 58 | model: 59 | os_family: Unknown 60 | browser_family: Unknown 61 | - 62 | user_agent: FeedDemon/4.5 (http://www.feeddemon.com/; Microsoft Windows) 63 | os: 64 | name: Windows 65 | short_name: WIN 66 | version: 67 | platform: 68 | client: 69 | type: feed reader 70 | name: FeedDemon 71 | version: "4.5" 72 | device: 73 | type: desktop 74 | brand: 75 | model: 76 | os_family: Windows 77 | browser_family: Unknown 78 | - 79 | user_agent: FeedDemon/4.5 (http://www.feeddemon.com/; Microsoft Windows XP) 80 | os: 81 | name: Windows 82 | short_name: WIN 83 | version: "XP" 84 | platform: 85 | client: 86 | type: feed reader 87 | name: FeedDemon 88 | version: "4.5" 89 | device: 90 | type: desktop 91 | brand: 92 | model: 93 | os_family: Windows 94 | browser_family: Unknown 95 | - 96 | user_agent: FeeddlerPro/2.4 CFNetwork/672.0.8 Darwin/14.0.0 97 | os: 98 | name: iOS 99 | short_name: IOS 100 | version: "7.0" 101 | platform: 102 | client: 103 | type: feed reader 104 | name: Feeddler RSS Reader 105 | version: "2.4" 106 | device: 107 | type: 108 | brand: AP 109 | model: 110 | os_family: iOS 111 | browser_family: Unknown 112 | - 113 | user_agent: FeeddlerRSS/2.4 CFNetwork/548.1.4 Darwin/11.0.0 114 | os: 115 | name: iOS 116 | short_name: IOS 117 | version: "5.1" 118 | platform: 119 | client: 120 | type: feed reader 121 | name: Feeddler RSS Reader 122 | version: "2.4" 123 | device: 124 | type: 125 | brand: AP 126 | model: 127 | os_family: iOS 128 | browser_family: Unknown 129 | - 130 | user_agent: FeeddlerRSS 2.4 (iPad; iPhone OS 5.1.1; en_US) 131 | os: 132 | name: iOS 133 | short_name: IOS 134 | version: "5.1.1" 135 | platform: 136 | client: 137 | type: feed reader 138 | name: Feeddler RSS Reader 139 | version: "2.4" 140 | device: 141 | type: tablet 142 | brand: AP 143 | model: iPad 144 | os_family: iOS 145 | browser_family: Unknown 146 | - 147 | user_agent: JetBrains Omea Reader 2.2 (http://www.jetbrains.com/omea/reader/) 148 | os: [ ] 149 | client: 150 | type: feed reader 151 | name: JetBrains Omea Reader 152 | version: "2.2" 153 | device: 154 | type: 155 | brand: 156 | model: 157 | os_family: Unknown 158 | browser_family: Unknown 159 | - 160 | user_agent: Liferea/1.6.4 (Linux; en_US.UTF-8; http://liferea.sf.net/) 161 | os: 162 | name: GNU/Linux 163 | short_name: LIN 164 | version: 165 | platform: 166 | client: 167 | type: feed reader 168 | name: Liferea 169 | version: "1.6.4" 170 | device: 171 | type: desktop 172 | brand: 173 | model: 174 | os_family: GNU/Linux 175 | browser_family: Unknown 176 | - 177 | user_agent: Liferea/1.10-RC1 (Linux; en_GB.UTF-8; http://liferea.sf.net/) 178 | os: 179 | name: GNU/Linux 180 | short_name: LIN 181 | version: 182 | platform: 183 | client: 184 | type: feed reader 185 | name: Liferea 186 | version: "1.10" 187 | device: 188 | type: desktop 189 | brand: 190 | model: 191 | os_family: GNU/Linux 192 | browser_family: Unknown 193 | - 194 | user_agent: Liferea/1.10.6 (Linux; en_US.UTF8; http://liferea.sf.net/) AppleWebKit (KHTML, like Gecko) 195 | os: 196 | name: GNU/Linux 197 | short_name: LIN 198 | version: 199 | platform: 200 | client: 201 | type: feed reader 202 | name: Liferea 203 | version: "1.10.6" 204 | device: 205 | type: desktop 206 | brand: 207 | model: 208 | os_family: GNU/Linux 209 | browser_family: Unknown 210 | - 211 | user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.74.9 (KHTML, like Gecko) Version/6.0 NetNewsWire/4.0.0 212 | os: 213 | name: Mac 214 | short_name: MAC 215 | version: "10.9.2" 216 | platform: 217 | client: 218 | type: feed reader 219 | name: NetNewsWire 220 | version: "4.0.0" 221 | device: 222 | type: desktop 223 | brand: 224 | model: 225 | os_family: Mac 226 | browser_family: Unknown 227 | - 228 | user_agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.74.9 (KHTML, like Gecko) NetNewsWire/3.3.2 229 | os: 230 | name: Mac 231 | short_name: MAC 232 | version: "10.9.2" 233 | platform: 234 | client: 235 | type: feed reader 236 | name: NetNewsWire 237 | version: "3.3.2" 238 | device: 239 | type: desktop 240 | brand: 241 | model: 242 | os_family: Mac 243 | browser_family: Unknown 244 | - 245 | user_agent: NetNewsWire/4.0.0 (Mac OS X; http://netnewswireapp.com/mac/; gzip-happy) 246 | os: 247 | name: Mac 248 | short_name: MAC 249 | version: 250 | platform: 251 | client: 252 | type: feed reader 253 | name: NetNewsWire 254 | version: "4.0.0" 255 | device: 256 | type: desktop 257 | brand: 258 | model: 259 | os_family: Mac 260 | browser_family: Unknown 261 | - 262 | user_agent: newsbeuter/2.7 (Linux x86_64) 263 | os: 264 | name: GNU/Linux 265 | short_name: LIN 266 | version: 267 | platform: x64 268 | client: 269 | type: feed reader 270 | name: Newsbeuter 271 | version: "2.7" 272 | device: 273 | type: desktop 274 | brand: 275 | model: 276 | os_family: GNU/Linux 277 | browser_family: Unknown 278 | - 279 | user_agent: NewsBlur iPhone App v3.6 280 | os: 281 | name: iOS 282 | short_name: IOS 283 | version: 284 | platform: 285 | client: 286 | type: feed reader 287 | name: NewsBlur Mobile App 288 | version: "3.6" 289 | device: 290 | type: smartphone 291 | brand: AP 292 | model: iPhone 293 | os_family: iOS 294 | browser_family: Unknown 295 | - 296 | user_agent: NewsBlur iPad App v3.6 297 | os: 298 | name: iOS 299 | short_name: IOS 300 | version: 301 | platform: 302 | client: 303 | type: feed reader 304 | name: NewsBlur Mobile App 305 | version: "3.6" 306 | device: 307 | type: tablet 308 | brand: AP 309 | model: iPad 310 | os_family: iOS 311 | browser_family: Unknown 312 | - 313 | user_agent: NewsBlur/4.0.1 CFNetwork/672.1.13 Darwin/14.0.0 314 | os: 315 | name: iOS 316 | short_name: IOS 317 | version: "7.1" 318 | platform: 319 | client: 320 | type: feed reader 321 | name: NewsBlur 322 | version: "4.0.1" 323 | device: 324 | type: 325 | brand: AP 326 | model: 327 | os_family: iOS 328 | browser_family: Unknown 329 | - 330 | user_agent: newsbeuter/2.4 (Linux 3.2.0-23-generic; i686; http://www.newsbeuter.org/) libcurl/7.22.0 GnuTLS/2.12.14 zlib/1.2.3.4 libidn/1.23 librtmp/2.3 331 | os: 332 | name: GNU/Linux 333 | short_name: LIN 334 | version: 335 | platform: x86 336 | client: 337 | type: feed reader 338 | name: Newsbeuter 339 | version: "2.4" 340 | device: 341 | type: desktop 342 | brand: 343 | model: 344 | os_family: GNU/Linux 345 | browser_family: Unknown 346 | - 347 | user_agent: Pulp/1.5.2 (iPad; http://www.acrylicapps.com/pulp/) 348 | os: 349 | name: iOS 350 | short_name: IOS 351 | version: 352 | platform: 353 | client: 354 | type: feed reader 355 | name: Pulp 356 | version: "1.5.2" 357 | device: 358 | type: tablet 359 | brand: AP 360 | model: iPad 361 | os_family: iOS 362 | browser_family: Unknown 363 | - 364 | user_agent: ReadKit/2.4.0 (Mac OS X Version 10.9.2 (Build 13C64)) 365 | os: 366 | name: Mac 367 | short_name: MAC 368 | version: "10.9.2" 369 | platform: 370 | client: 371 | type: feed reader 372 | name: ReadKit 373 | version: "2.4.0" 374 | device: 375 | type: desktop 376 | brand: 377 | model: 378 | os_family: Mac 379 | browser_family: Unknown 380 | - 381 | user_agent: ReadKit/7017 CFNetwork/673.2.1 Darwin/13.1.0 (x86_64) (MacBookPro10%2C1) 382 | os: 383 | name: Mac 384 | short_name: MAC 385 | version: "10.9" 386 | platform: x64 387 | client: 388 | type: feed reader 389 | name: ReadKit 390 | version: "7017" 391 | device: 392 | type: desktop 393 | brand: AP 394 | model: 395 | os_family: Mac 396 | browser_family: Unknown 397 | - 398 | user_agent: Reeder/3.2 CFNetwork/672.1.12 Darwin/14.0.0 399 | os: 400 | name: iOS 401 | short_name: IOS 402 | version: "7.1" 403 | platform: 404 | client: 405 | type: feed reader 406 | name: Reeder 407 | version: "3.2" 408 | device: 409 | type: 410 | brand: AP 411 | model: 412 | os_family: iOS 413 | browser_family: Unknown 414 | - 415 | user_agent: RssBandit/1.9.0.1002 416 | os: [ ] 417 | client: 418 | type: feed reader 419 | name: RSS Bandit 420 | version: "1.9.0.1002" 421 | device: 422 | type: 423 | brand: 424 | model: 425 | os_family: Unknown 426 | browser_family: Unknown 427 | - 428 | user_agent: RssBandit/1.9.0.1002 (.NET CLR 2.0.50727.7512; WinNT 6.2.9200.0; http://www.rssbandit.org) 429 | os: 430 | name: Windows 431 | short_name: WIN 432 | version: "NT" 433 | platform: 434 | client: 435 | type: feed reader 436 | name: RSS Bandit 437 | version: "1.9.0.1002" 438 | device: 439 | type: desktop 440 | brand: 441 | model: 442 | os_family: Windows 443 | browser_family: Unknown 444 | - 445 | user_agent: RSS Junkie Daemon 446 | os: [ ] 447 | client: 448 | type: feed reader 449 | name: RSS Junkie 450 | version: 451 | device: 452 | type: 453 | brand: 454 | model: 455 | os_family: Unknown 456 | browser_family: Unknown 457 | - 458 | user_agent: RSSOwl/2.2.1.201312301314 (Windows; U; en) 459 | os: 460 | name: Windows 461 | short_name: WIN 462 | version: 463 | platform: 464 | client: 465 | type: feed reader 466 | name: RSSOwl 467 | version: "2.2.1.201312301314" 468 | device: 469 | type: desktop 470 | brand: 471 | model: 472 | os_family: Windows 473 | browser_family: Unknown 474 | - 475 | user_agent: RSSOwl/2.2.1.201312301316 (X11; U; en) 476 | os: [ ] 477 | client: 478 | type: feed reader 479 | name: RSSOwl 480 | version: "2.2.1.201312301316" 481 | device: 482 | type: 483 | brand: 484 | model: 485 | os_family: Unknown 486 | browser_family: Unknown 487 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DeviceDetector 2 | 3 | ![Podigee DeviceDetector Travisci Badge](https://travis-ci.org/podigee/device_detector.svg) 4 | 5 | DeviceDetector is a precise and fast user agent parser and device detector written in Ruby, backed by the largest and most up-to-date user agent database. 6 | 7 | DeviceDetector will parse any user agent and detect the browser, operating system, device used (desktop, tablet, mobile, tv, cars, console, etc.), brand and model. DeviceDetector detects thousands of user agent strings, even from rare and obscure browsers and devices. 8 | 9 | The DeviceDetector is optimized for speed of detection, by providing optimized code and in-memory caching. 10 | 11 | This project originated as a Ruby port of the Universal Device Detection library. 12 | You can find the original code here: https://github.com/piwik/device-detector. 13 | 14 | ## Disclaimer 15 | 16 | This port does not aspire to be a one-to-one copy from the original code, but rather an adaptation for the Ruby language. 17 | 18 | Still, our goal is to use the original, unchanged regex yaml files, in order to mutually benefit from updates and pull request to both the original and the ported versions. 19 | 20 | ## Installation 21 | 22 | Add this line to your application's Gemfile: 23 | 24 | ```ruby 25 | gem 'device_detector' 26 | ``` 27 | 28 | And then execute: 29 | 30 | $ bundle 31 | 32 | Or install it yourself as: 33 | 34 | $ gem install device_detector 35 | 36 | ## Usage 37 | 38 | ```ruby 39 | user_agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36' 40 | client = DeviceDetector.new(user_agent) 41 | 42 | client.name # => 'Chrome' 43 | client.full_version # => '30.0.1599.69' 44 | 45 | client.os_name # => 'Windows' 46 | client.os_full_version # => '8' 47 | 48 | # For many devices, you can also query the device name (usually the model name) 49 | client.device_name # => 'iPhone 5' 50 | # Device types can be one of the following: desktop, smartphone, tablet, console, 51 | # portable media player, tv, car browser, camera 52 | client.device_type # => 'smartphone' 53 | ``` 54 | 55 | `DeviceDetector` will return `nil` on all attributes, if the `user_agent` is unknown. 56 | You can make a check to ensure the client has been detected: 57 | 58 | ```ruby 59 | client.known? # => will return false if user_agent is unknown 60 | ``` 61 | 62 | ### Memory cache 63 | 64 | `DeviceDetector` will cache up 5,000 user agent strings to boost parsing performance. 65 | You can tune the amount of keys that will get saved in the cache. You have to call this code **before** you initialize the Detector. 66 | 67 | ```ruby 68 | DeviceDetector.configure do |config| 69 | config.max_cache_keys = 5_000 # increment this if you have enough RAM, proceed with care 70 | end 71 | ``` 72 | 73 | If you have a Rails application, you can create an initializer, for example `config/initializers/device_detector.rb`. 74 | 75 | ## Benchmarks 76 | 77 | We have measured the parsing speed of almost 200,000 non-unique user agent strings and compared the speed of DeviceDetector with the two most popular user agent parsers in the Ruby community, Browser and UserAgent. 78 | 79 | ### Testing machine specs 80 | 81 | - MacBook Pro 15", Late 2013 82 | - 2.6 GHz Intel Core i7 83 | - 16 GB 1600 MHz DDR3 84 | 85 | ### Gem versions 86 | 87 | - DeviceDetector - 0.5.1 88 | - Browser - 0.8.0 89 | - UserAgent - 0.13.1 90 | 91 | ### Code 92 | 93 | ```ruby 94 | require 'device_detector' 95 | require 'browser' 96 | require 'user_agent' 97 | require 'benchmark' 98 | 99 | user_agent_strings = File.read('./tmp/user_agent_strings.txt').split("\n") 100 | 101 | ## Benchmarks 102 | 103 | Benchmark.bm(15) do |x| 104 | x.report('device_detector') { 105 | user_agent_strings.each { |uas| DeviceDetector.new(uas).name } 106 | } 107 | x.report('browser') { 108 | user_agent_strings.each { |uas| Browser.new(ua: uas).name } 109 | } 110 | x.report('useragent') { 111 | user_agent_strings.each { |uas| UserAgent.parse(uas).browser } 112 | } 113 | end 114 | ``` 115 | 116 | ### Results 117 | 118 | ``` 119 | user system total real 120 | device_detector 1.180000 0.010000 1.190000 ( 1.198721) 121 | browser 2.240000 0.010000 2.250000 ( 2.245493) 122 | useragent 4.490000 0.020000 4.510000 ( 4.500673) 123 | 124 | user system total real 125 | device_detector 1.190000 0.020000 1.210000 ( 1.201447) 126 | browser 2.250000 0.010000 2.260000 ( 2.261001) 127 | useragent 4.440000 0.010000 4.450000 ( 4.451693) 128 | 129 | user system total real 130 | device_detector 1.210000 0.020000 1.230000 ( 1.228617) 131 | browser 2.220000 0.010000 2.230000 ( 2.222565) 132 | useragent 4.450000 0.000000 4.450000 ( 4.452741) 133 | ``` 134 | 135 | ## Detectable clients, bots and devices 136 | 137 | Updated on 2016-07-16 138 | 139 | ### Bots 140 | 141 | 360Spider, Aboundexbot, Acoon, AddThis.com, ADMantX, aHrefs Bot, Alexa Crawler, Amorank Spider, Analytics SEO Crawler, Applebot, archive.org bot, Ask Jeeves, Backlink-Ceck.de, BacklinkCrawler, Baidu Spider, BazQux Reader, BingBot, Blekkobot, BLEXBot Crawler, Bloglovin, Blogtrottr, Bountii Bot, Browsershots, BUbiNG, Butterfly Robot, CareerBot, ccBot crawler, Charlotte, Cliqzbot, CloudFlare Always Online, CommaFeed, Cốc Cốc Bot, Daum, Dazoobot, Discobot, Domain Re-Animator Bot, DotBot, Easou Spider, EMail Exractor, EmailWolf, ExaBot, ExactSeek Crawler, Ezooms, Facebook External Hit, Feed Wrangler, Feedbin, FeedBurner, Feedly, Feedspot, Fever, Generic Bot, Genieo Web filter, Gigabot, Gluten Free Crawler, Gmail Image Proxy, Goo, Google PageSpeed Insights, Google Partner Monitoring, Googlebot, Heritrix, HTTPMon, HubPages, ICC-Crawler, ichiro, IIS Site Analysis, Inktomi Slurp, Kouio, Larbin web crawler, Linkdex Bot, LinkedIn Bot, LTX71, Lycos, Magpie-Crawler, MagpieRSS, Mail.Ru Bot, Meanpath Bot, Mixrank Bot, MJ12 Bot, MojeekBot, Monitor.Us, NalezenCzBot, Netcraft Survey Bot, NetLyzer FastProbe, NetResearchServer, Netvibes, NewsBlur, NewsGator, NLCrawler, Nutch-based Bot, Omgili bot, Openindex Spider, OpenLinkProfiler, OpenWebSpider, Orange Bot, Outbrain, PagePeeker, PaperLiBot, PHP Server Monitor, Picsearch bot, Pingdom Bot, Pinterest, Pompos, QuerySeekerSpider, Reddit Bot, Rogerbot, ROI Hunter, Scooter, ScoutJet, Scrapy, Screaming Frog SEO Spider, ScreenerBot, Semrush Bot, Sensika Bot, SEOENGBot, Server Density, Seznam Bot, ShopWiki, SilverReader, SimplePie, SISTRIX Crawler, Site24x7 Website Monitoring, Skype URI Preview, Slackbot, Sogou Spider, Soso Spider, Speedy, Spinn3r, Sputnik Bot, Superfeedr Bot, Survey Bot, TelgramBot, TinEye Crawler, Tiny Tiny RSS, TurnitinBot, TweetedTimes Bot, Tweetmeme Bot, Twitterbot, Uptime Robot, URLAppendBot, Visual Site Mapper Crawler, W3C CSS Validator, W3C I18N Checker, W3C Link Checker, W3C Markup Validation Service, W3C MobileOK Checker, W3C Unified Validator, WebbCrawler, WebSitePulse, WebThumbnail, WeSEE:Search, Willow Internet Crawler, Wotbox, YaCy, Yahoo Gemini, Yahoo! Cache System, Yahoo! Link Preview, Yahoo! Slurp, Yandex Bot, Yeti/Naverbot, Yottaa Site Monitor, Youdao Bot, Yourls, Yunyun Bot, Zao, Zookabot, ZumBot 142 | 143 | ### Clients 144 | 145 | 360 Browser, 360 Phone Browser, ABrowse, Airmail, Akregator, Amaya, Amiga Aweb, Amiga Voyager, Amigo, Android Browser, AndroidDownloadManager, ANT Fresco, ANTGalio, Apple PubSub, Arora, Atomic Web Browser, Avant Browser, Baidu Browser, Baidu Spark, Banshee, Barca, Beonex, BlackBerry Browser, Boxee, Brave, BrowseX, Bunjalloo, Camino, Charon, Cheshire, Chrome, Chrome Frame, Chrome Mobile, Chrome Mobile iOS, ChromePlus, Chromium, Clementine, Coc Coc, CometBird, Comodo Dragon, Conkeror, CoolNovo, curl, Deepnet Explorer, Dillo, Dolphin, Element Browser, Elinks, Epiphany, Espial TV Browser, Facebook, FeedDemon, Feeddler RSS Reader, FeedR, Fennec, Firebird, Firefox, Fireweb, Fireweb Navigator, Flock, Fluid, FlyCast, Galeon, Google Earth, Google Play Newsstand, Google Plus, Guzzle (PHP HTTP Client), HotJava, IBrowse, iCab, IceDragon, Iceweasel, IE Mobile, Instacast, Internet Explorer, Iron, iTunes, Jasmine, Java, JetBrains Omea Reader, Jig Browser, K-meleon, Kapiko, Kazehakase, Kindle Browser, Kodi, Konqueror, Kylo, LG Browser, Liebao, Liferea, Line, Links, Lotus Notes, LuaKit, Lunascape, Lynx, MailBar, Maxthon, MediaMonkey, Mercury, MicroB, Microsoft Edge, Microsoft Outlook, Midori, Miro, MIUI Browser, Mobile Safari, Mobile Silk, NCSA Mosaic, NetFront, NetFront Life, NetNewsWire, NetPositive, Netscape, Newsbeuter, NewsBlur, NewsBlur Mobile App, NexPlayer, Nightingale, Nokia Browser, Nokia OSS Browser, Nokia Ovi Browser, Obigo, Odyssey Web Browser, Off By One, OmniWeb, ONE Browser, Openwave Mobile Browser, Opera, Opera Mini, Opera Mobile, Opera Next, Oregano, Otter Browser, Outlook Express, Pale Moon, Palm Blazer, Palm Pre, Palm WebPro, Palmscape, Perl, Phoenix, Pinterest, Polaris, Postbox, Puffin, Pulp, Python Requests, Python urllib, QQ Browser, QuickTime, ReadKit, Reeder, Rekonq, RockMelt, RSS Bandit, RSS Junkie, RSSOwl, Safari, Sailfish Browser, Samsung Browser, SEMC-Browser, Seraphic Sraf, Shiira, Sina Weibo, Skyfire, Sleipnir, Snowshoe, Sogou Explorer, Songbird, Stagefright, Stringer, SubStream, Sunrise, SuperBird, Swiftfox, The Bat!, Thunderbird, Tizen Browser, TweakStyle, UC Browser, Vision Mobile Browser, Vivaldi, VLC, WebPositive, WeChat, WeTab Browser, Wget, WhatsApp, Winamp, Windows Media Player, wOSBrowser, XBMC, Xiino, Yandex Browser, YouTube 146 | 147 | ### Devices 148 | 149 | 3Q, Acer, Ainol, Airness, Airties, Alcatel, Allview, Altech UEC, Amazon, Amoi, Apple, Archos, Arnova, ARRIS, Asus, Audiovox, Avvio, Axxion, BangOlufsen, Barnes & Noble, Becker, Beetel, BenQ, BenQ-Siemens, Bird, Blu, Bmobile, Boway, bq, Brondi, Bush, Capitel, Captiva, Carrefour, Casio, Cat, Celkon, Changhong, Cherry Mobile, CnM, Coby Kyros, Compal, ConCorde, Coolpad, Cowon, CreNova, Cricket, Crius Mea, Crosscall, Cube, CUBOT, Danew, Datang, Dbtel, Dell, Denver, Desay, Dicam, DMM, DNS, DoCoMo, Doogee, Doov, Dopod, Dune HD, E-Boda, Easypix, EBEST, ECS, Elephone, Energy Sistem, Ericsson, Ericy, Eton, eTouch, Evertek, Ezio, Ezze, Fairphone, Fly, Foxconn, Fujitsu, Garmin-Asus, Gemini, Gigabyte, Gigaset, Gionee, GOCLEVER, Goly, Google, Gradiente, Grundig, Haier, Hasee, Hi-Level, Hisense, Hosin, HP, HTC, Huawei, Humax, Hyundai, i-Joy, i-mate, i-mobile, iBall, iBerry, Ikea, iKoMo, iNew, Infinix, Inkti, Innostream, INQ, Intek, Intex, Inverto, iOcean, iTel, Jiayu, Jolla, K-Touch, Karbonn, Kazam, KDDI, Kingsun, Komu, Konka, Koobee, KOPO, Koridy, KT-Tech, Kumai, Kyocera, Lanix, Lava, LCT, Le Pan, Lenco, Lenovo, Lexibook, LG, Lingwin, Loewe, Logicom, M.T.T., Majestic, Manta Multimedia, Mecer, Mediacom, MediaTek, Medion, MEEG, Meizu, Memup, Metz, MEU, MicroMax, Microsoft, Mio, Mitsubishi, MLLED, Mobistel, Mofut, Motorola, Mpman, MSI, MyPhone, NEC, Netgear, Newgen, Nexian, NextBook, NGM, Nikon, Nintendo, Noain, Nokia, Nomi, O2, Onda, OnePlus, OPPO, Opsson, Orange, Ouki, OUYA, Overmax, Oysters, Palm, Panasonic, Pantech, PEAQ, Philips, phoneOne, Pioneer, Ployer, Point of View, Polaroid, PolyPad, Pomp, Positivo, Prestigio, ProScan, PULID, Qilive, QMobile, Qtek, Quechua, Ramos, RCA Tablets, Readboy, Rikomagic, RIM, Roku, Rover, Sagem, Samsung, Sanyo, Sega, Selevision, Sencor, Sendo, SFR, Sharp, Siemens, Skyworth, Smart, Smartfren, Softbank, Sony, Spice, Star, Stonex, Storex, Sumvision, SunVan, SuperSonic, Symphony, T-Mobile, TCL, TechniSat, TechnoTrend, Tecno Mobile, Telefunken, Telenor, Telit, Tesco, Tesla, teXet, ThL, Thomson, TIANYU, TiPhone, Tolino, Toplux, Toshiba, Trevi, Tunisie Telecom, Turbo-X, TVC, Uniscope, Unknown, Unowhy, UTStarcom, Vastking, Vertu, Vestel, Videocon, Videoweb, ViewSonic, Vitelcom, Vivo, Vizio, VK Mobile, Vodafone, Voto, Voxtel, Walton, WellcoM, Wexler, Wiko, Wolder, Wonu, Woxter, Xiaomi, Xolo, Yarvik, Ytone, Yuandao, Yusun, Zeemi, Zonda, Zopo, ZTE 150 | 151 | ## Maintainers 152 | 153 | - Mati Sojka: https://github.com/yagooar 154 | - Ben Zimmer: https://github.com/benzimmer 155 | 156 | ## Contributors 157 | 158 | Thanks a lot to the following contributors: 159 | 160 | - Peter Gao: https://github.com/peteygao 161 | 162 | ## Contributing 163 | 164 | 1. Open an issue and explain your feature request or bug before writing any code (this can save a lot of time, both the contributor and the maintainers!) 165 | 2. Fork the project (https://github.com/podigee/device_detector/fork) 166 | 3. Create your feature branch (`git checkout -b my-new-feature`) 167 | 4. Commit your changes (`git commit -am 'Add some feature'`) 168 | 5. Push to the branch (`git push origin my-new-feature`) 169 | 6. Create a new Pull Request (compare with develop) 170 | 7. When adding new data to the yaml files, please make sure to open a PR in the original project, as well (https://github.com/piwik/device-detector) 171 | -------------------------------------------------------------------------------- /regexes/oss.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | ########## 9 | # Tizen 10 | ########## 11 | - regex: 'Tizen[ /]?(\d+[\.\d]+)?' 12 | name: 'Tizen' 13 | version: '$1' 14 | 15 | 16 | 17 | ########## 18 | ## Sailfish OS 19 | ########### 20 | - regex: 'Sailfish|Jolla' 21 | name: 'Sailfish OS' 22 | version: '' 23 | 24 | ########## 25 | # YunOS (Android based) 26 | ########## 27 | - regex: '(?:Ali)?YunOS[ /]?(\d+[\.\d]+)?' 28 | name: 'YunOS' 29 | version: '$1' 30 | 31 | ########## 32 | # Windows Mobile 33 | ########## 34 | - regex: 'Windows Phone (?:OS)?[ ]?(\d+[\.\d]+)' 35 | name: 'Windows Phone' 36 | version: '$1' 37 | 38 | 39 | - regex: 'XBLWP7|Windows Phone' 40 | name: 'Windows Phone' 41 | version: '' 42 | 43 | - regex: 'Windows CE(?: (\d+[\.\d]+))?' 44 | name: 'Windows CE' 45 | version: '$1' 46 | 47 | 48 | - regex: '(?:IEMobile|Windows Mobile)(?: (\d+[\.\d]+))?' 49 | name: 'Windows Mobile' 50 | version: '$1' 51 | 52 | 53 | - regex: 'Windows NT 6.2; ARM;' 54 | name: 'Windows RT' 55 | version: '' 56 | 57 | - regex: 'Windows NT 6.3; ARM;' 58 | name: 'Windows RT' 59 | version: '8.1' 60 | 61 | 62 | ########## 63 | # Custom Android Roms 64 | ########## 65 | - regex: 'RazoDroiD(?: v(\d+[\.\d]*))?' 66 | name: 'RazoDroiD' 67 | version: '$1' 68 | 69 | - regex: 'MildWild(?: CM-(\d+[\.\d]*))?' 70 | name: 'MildWild' 71 | version: '$1' 72 | 73 | - regex: 'CyanogenMod(?:[\-/](?:CM)?(\d+[\.\d]*))?' 74 | name: 'CyanogenMod' 75 | version: '$1' 76 | 77 | - regex: '(?:.*_)?MocorDroid(?:(\d+[\.\d]*))?' 78 | name: 'MocorDroid' 79 | version: '$1' 80 | 81 | ########## 82 | # Android 83 | ########## 84 | - regex: '(?:(?:Orca-)?Android|Adr)[ /](?:[a-z]+ )?(\d+[\.\d]+)' 85 | name: 'Android' 86 | version: '$1' 87 | 88 | 89 | - regex: 'Android|Silk-Accelerated=[a-z]{4,5}' 90 | name: 'Android' 91 | version: '' 92 | 93 | 94 | ########## 95 | # AmigaOS 96 | ########## 97 | - regex: 'AmigaOS[ ]?(\d+[\.\d]+)' 98 | name: 'AmigaOS' 99 | version: '$1' 100 | 101 | - regex: 'AmigaOS|AmigaVoyager|Amiga-AWeb' 102 | name: 'AmigaOS' 103 | version: '' 104 | 105 | ########## 106 | # ThreadX 107 | ########## 108 | - regex: 'ThreadX(?:/(\d+[\.\d]*))?' 109 | name: 'ThreadX' 110 | version: '$1' 111 | 112 | ########## 113 | # MTK / Nucleus 114 | ########## 115 | - regex: 'Nucleus(?:(?: |/v?)(\d+[\.\d]*))?' 116 | name: 'MTK / Nucleus' 117 | version: '$1' 118 | - regex: 'MTK(?:(?: |/v?)(\d+[\.\d]*))?' 119 | name: 'MTK / Nucleus' 120 | version: '$1' 121 | 122 | ########## 123 | # Linux 124 | ########## 125 | - regex: 'Maemo' 126 | name: 'Maemo' 127 | version: '$1' 128 | 129 | - regex: 'Arch ?Linux(?:[ /\-](\d+[\.\d]+))?' 130 | name: 'Arch Linux' 131 | version: '$1' 132 | 133 | - regex: 'VectorLinux(?: package)?(?:[ /\-](\d+[\.\d]+))?' 134 | name: 'VectorLinux' 135 | version: '$1' 136 | 137 | - regex: 'Linux; .*((?:Debian|Knoppix|Mint|Ubuntu|Kubuntu|Xubuntu|Lubuntu|Fedora|Red Hat|Mandriva|Gentoo|Sabayon|Slackware|SUSE|CentOS|BackTrack))[ /](\d+[\.\d]+)' 138 | name: '$1' 139 | version: '$2' 140 | 141 | - regex: '(Debian|Knoppix|Mint|Ubuntu|Kubuntu|Xubuntu|Lubuntu|Fedora|Red Hat|Mandriva|Gentoo|Sabayon|Slackware|SUSE|CentOS|BackTrack)(?:(?: Enterprise)? Linux)?(?:[ /\-](\d+[\.\d]+))?' 142 | name: '$1' 143 | version: '$2' 144 | 145 | # generic linux match -> end of file 146 | 147 | ########## 148 | # webOS 149 | ########## 150 | - regex: '(?:webOS|Palm webOS)(?:/(\d+[\.\d]+))?' 151 | name: 'webOS' 152 | version: '$1' 153 | 154 | - regex: '(?:PalmOS|Palm OS)(?:[/ ](\d+[\.\d]+))?|Palm' 155 | name: 'palmOS' 156 | version: '$1' 157 | 158 | - regex: 'Xiino(?:.*v\. (\d+[\.\d]+))?' # palmOS only browser 159 | name: 'palmOS' 160 | version: '$1' 161 | 162 | 163 | - regex: 'MorphOS(?:[ /](\d+[\.\d]+))?' 164 | name: 'MorphOS' 165 | version: '$1' 166 | 167 | 168 | ########## 169 | # Windows 170 | ########## 171 | - regex: 'CYGWIN_NT-10.0|Windows NT 10.0|Windows 10' 172 | name: 'Windows' 173 | version: '10' 174 | 175 | - regex: 'CYGWIN_NT-6.4|Windows NT 6.4|Windows 10' 176 | name: 'Windows' 177 | version: '10' 178 | 179 | - regex: 'CYGWIN_NT-6.3|Windows NT 6.3|Windows 8.1' 180 | name: 'Windows' 181 | version: '8.1' 182 | 183 | 184 | - regex: 'CYGWIN_NT-6.2|Windows NT 6.2|Windows 8' 185 | name: 'Windows' 186 | version: '8' 187 | 188 | 189 | - regex: 'CYGWIN_NT-6.1|Windows NT 6.1|Windows 7' 190 | name: 'Windows' 191 | version: '7' 192 | 193 | 194 | - regex: 'CYGWIN_NT-6.0|Windows NT 6.0|Windows Vista' 195 | name: 'Windows' 196 | version: 'Vista' 197 | 198 | 199 | - regex: 'CYGWIN_NT-5.2|Windows NT 5.2|Windows Server 2003 / XP x64' 200 | name: 'Windows' 201 | version: 'Server 2003' 202 | 203 | 204 | - regex: 'CYGWIN_NT-5.1|Windows NT 5.1|Windows XP' 205 | name: 'Windows' 206 | version: 'XP' 207 | 208 | 209 | - regex: 'CYGWIN_NT-5.0|Windows NT 5.0|Windows 2000' 210 | name: 'Windows' 211 | version: '2000' 212 | 213 | 214 | - regex: 'CYGWIN_NT-4.0|Windows NT 4.0|WinNT|Windows NT' 215 | name: 'Windows' 216 | version: 'NT' 217 | 218 | 219 | - regex: 'CYGWIN_ME-4.90|Win 9x 4.90|Windows ME' 220 | name: 'Windows' 221 | version: 'ME' 222 | 223 | 224 | - regex: 'CYGWIN_98-4.10|Win98|Windows 98' 225 | name: 'Windows' 226 | version: '98' 227 | 228 | 229 | - regex: 'CYGWIN_95-4.0|Win32|Win95|Windows 95|Windows_95' 230 | name: 'Windows' 231 | version: '95' 232 | 233 | 234 | - regex: 'Windows 3.1' 235 | name: 'Windows' 236 | version: '3.1' 237 | 238 | 239 | - regex: 'Windows' 240 | name: 'Windows' 241 | version: '' 242 | 243 | 244 | 245 | ########## 246 | # iOS 247 | ########## 248 | - regex: 'CFNetwork/758\.4\.3' 249 | name: 'iOS' 250 | version: '9.3.2' 251 | 252 | - regex: 'CFNetwork/758\.3\.15' 253 | name: 'iOS' 254 | version: '9.3' 255 | 256 | - regex: 'CFNetwork/758\.2\.[78]' 257 | name: 'iOS' 258 | version: '9.2' 259 | 260 | - regex: 'CFNetwork/758\.1\.6' 261 | name: 'iOS' 262 | version: '9.1' 263 | 264 | - regex: 'CFNetwork/758\.0\.2' 265 | name: 'iOS' 266 | version: '9.0' 267 | 268 | - regex: 'CFNetwork/711\.5\.6' 269 | name: 'iOS' 270 | version: '8.4.1' 271 | 272 | - regex: 'CFNetwork/711\.4\.6' 273 | name: 'iOS' 274 | version: '8.4' 275 | 276 | - regex: 'CFNetwork/711\.3\.18' 277 | name: 'iOS' 278 | version: '8.3' 279 | 280 | - regex: 'CFNetwork/711\.2\.23' 281 | name: 'iOS' 282 | version: '8.2' 283 | 284 | - regex: 'CFNetwork/711\.1\.1[26]' 285 | name: 'iOS' 286 | version: '8.1' 287 | 288 | - regex: 'CFNetwork/711\.0\.6' 289 | name: 'iOS' 290 | version: '8.0' 291 | 292 | - regex: 'CFNetwork/672\.1' 293 | name: 'iOS' 294 | version: '7.1' 295 | 296 | - regex: 'CFNetwork/672\.0' 297 | name: 'iOS' 298 | version: '7.0' 299 | 300 | - regex: 'CFNetwork/609\.1' 301 | name: 'iOS' 302 | version: '6.1' 303 | 304 | - regex: 'CFNetwork/60[29]' 305 | name: 'iOS' 306 | version: '6.0' 307 | 308 | - regex: 'CFNetwork/548\.1' 309 | name: 'iOS' 310 | version: '5.1' 311 | 312 | - regex: 'CFNetwork/548\.0' 313 | name: 'iOS' 314 | version: '5.0' 315 | 316 | - regex: 'CFNetwork/485\.13' 317 | name: 'iOS' 318 | version: '4.3' 319 | 320 | - regex: 'CFNetwork/485\.12' 321 | name: 'iOS' 322 | version: '4.2' 323 | 324 | - regex: 'CFNetwork/485\.10' 325 | name: 'iOS' 326 | version: '4.1' 327 | 328 | - regex: 'CFNetwork/485\.2' 329 | name: 'iOS' 330 | version: '4.0' 331 | 332 | - regex: 'CFNetwork/467\.12' 333 | name: 'iOS' 334 | version: '3.2' 335 | 336 | - regex: 'CFNetwork/459' 337 | name: 'iOS' 338 | version: '3.1' 339 | 340 | - regex: '(?:CPU OS|iPh(?:one)?[ _]OS|iOS)[ _/](\d+(?:[_\.]\d+)*)' 341 | name: 'iOS' 342 | version: '$1' 343 | 344 | - regex: '(?:Apple-)?(?:iPhone|iPad|iPod)(?:.*Mac OS X.*Version/(\d+\.\d+)|; Opera)?' 345 | name: 'iOS' 346 | version: '$1' 347 | 348 | 349 | 350 | ########## 351 | # Mac 352 | ########## 353 | 354 | - regex: 'CFNetwork/760' 355 | name: 'Mac' 356 | version: '10.11' 357 | 358 | - regex: 'CFNetwork/720' 359 | name: 'Mac' 360 | version: '10.10' 361 | 362 | - regex: 'CFNetwork/673' 363 | name: 'Mac' 364 | version: '10.9' 365 | 366 | - regex: 'CFNetwork/596' 367 | name: 'Mac' 368 | version: '10.8' 369 | 370 | - regex: 'CFNetwork/520' 371 | name: 'Mac' 372 | version: '10.7' 373 | 374 | - regex: 'CFNetwork/454' 375 | name: 'Mac' 376 | version: '10.6' 377 | 378 | - regex: 'CFNetwork/(?:438|422|339|330|221|220|217)' 379 | name: 'Mac' 380 | version: '10.5' 381 | 382 | - regex: 'CFNetwork/12[89]' 383 | name: 'Mac' 384 | version: '10.4' 385 | 386 | - regex: 'CFNetwork/1\.2' 387 | name: 'Mac' 388 | version: '10.3' 389 | 390 | - regex: 'CFNetwork/1\.1' 391 | name: 'Mac' 392 | version: '10.2' 393 | 394 | - regex: 'Mac OS X(?: (?:Version )?(\d+(?:[_\.]\d+)+))?' 395 | name: 'Mac' 396 | version: '$1' 397 | 398 | - regex: 'Mac (\d+(?:[_\.]\d+)+)' 399 | name: 'Mac' 400 | version: '$1' 401 | 402 | - regex: 'Darwin|Macintosh|Mac_PowerPC|PPC|Mac PowerPC' 403 | name: 'Mac' 404 | version: '' 405 | 406 | 407 | 408 | ########## 409 | # ChromeOS 410 | ########## 411 | - regex: 'CrOS [a-z0-9_]+ (\d+[\.\d]+)' 412 | name: 'Chrome OS' 413 | version: '$1' 414 | 415 | 416 | 417 | ########## 418 | # BlackBerry 419 | ########## 420 | - regex: '(?:BB10;.+Version|Black[Bb]erry[0-9a-z]+|Black[Bb]erry.+Version)/(\d+[\.\d]+)' 421 | name: 'BlackBerry OS' 422 | version: '$1' 423 | 424 | 425 | - regex: 'RIM Tablet OS (\d+[\.\d]+)' 426 | name: 'BlackBerry Tablet OS' 427 | version: '$1' 428 | 429 | 430 | - regex: 'RIM Tablet OS|QNX|Play[Bb]ook' 431 | name: 'BlackBerry Tablet OS' 432 | version: '' 433 | 434 | 435 | - regex: 'BlackBerry' 436 | name: 'BlackBerry OS' 437 | version: '' 438 | 439 | 440 | ########## 441 | # Haiku OS 442 | ########## 443 | - regex: 'Haiku' 444 | name: 'Haiku OS' 445 | version: '' 446 | 447 | 448 | ########## 449 | # BeOS 450 | ########## 451 | - regex: 'BeOS' 452 | name: 'BeOS' 453 | version: '' 454 | 455 | 456 | 457 | 458 | ########## 459 | # Symbian 460 | ########## 461 | - regex: 'Symbian/3.+NokiaBrowser/7\.3' 462 | name: 'Symbian^3' 463 | version: 'Anna' 464 | 465 | 466 | - regex: 'Symbian/3.+NokiaBrowser/7\.4' 467 | name: 'Symbian^3' 468 | version: 'Belle' 469 | 470 | 471 | - regex: 'Symbian/3' 472 | name: 'Symbian^3' 473 | version: '' 474 | 475 | 476 | - regex: '(?:Series ?60|SymbOS|S60)(?:[ /]?(\d+[\.\d]+|V\d+))?' 477 | name: 'Symbian OS Series 60' 478 | version: '$1' 479 | 480 | 481 | - regex: 'Series40' 482 | name: 'Symbian OS Series 40' 483 | version: '' 484 | 485 | 486 | - regex: 'SymbianOS/(\d+[\.\d]+)' 487 | name: 'Symbian OS' 488 | version: '$1' 489 | 490 | 491 | - regex: 'MeeGo|WeTab' 492 | name: 'MeeGo' 493 | version: '' 494 | 495 | 496 | - regex: 'Symbian(?: OS)?|SymbOS' 497 | name: 'Symbian OS' 498 | version: '' 499 | 500 | 501 | - regex: 'Nokia' 502 | name: 'Symbian' 503 | version: '' 504 | 505 | 506 | 507 | ########## 508 | # Firefox OS 509 | ########## 510 | - regex: '(?:Mobile|Tablet);.+Firefox/\d+\.\d+' 511 | name: 'Firefox OS' 512 | version: '' 513 | 514 | 515 | ########## 516 | # RISC OS 517 | ########## 518 | - regex: 'RISC OS(?:-NC)?(?:[ /](\d+[\.\d]+))?' 519 | name: 'RISC OS' 520 | version: '$1' 521 | 522 | 523 | ########## 524 | # Inferno 525 | ########## 526 | - regex: 'Inferno(?:[ /](\d+[\.\d]+))?' 527 | name: 'Inferno' 528 | version: '$1' 529 | 530 | 531 | ########## 532 | # Bada 533 | ########## 534 | - regex: 'bada(?:[ /](\d+[\.\d]+))' 535 | name: 'Bada' 536 | version: '$1' 537 | 538 | 539 | - regex: 'bada' 540 | name: 'Bada' 541 | version: '' 542 | 543 | 544 | ########## 545 | # Brew 546 | ########## 547 | - regex: '(?:Brew MP|BREW|BMP)(?:[ /](\d+[\.\d]+))' 548 | name: 'Brew' 549 | version: '$1' 550 | 551 | 552 | - regex: 'Brew MP|BREW|BMP' 553 | name: 'Brew' 554 | version: '' 555 | 556 | 557 | ########## 558 | # Web TV 559 | ########## 560 | - regex: 'GoogleTV(?:[ /](\d+[\.\d]+))?' 561 | name: 'Google TV' 562 | version: '$1' 563 | 564 | 565 | - regex: 'AppleTV(?:/?(\d+[\.\d]+))?' 566 | name: 'Apple TV' 567 | version: '$1' 568 | 569 | 570 | - regex: 'WebTV/(\d+[\.\d]+)' 571 | name: 'WebTV' 572 | version: '$1' 573 | 574 | 575 | ########## 576 | # Remix OS 577 | ########## 578 | - regex: 'RemixOS 5.1.1' 579 | name: 'Remix OS' 580 | version: '1' 581 | 582 | - regex: 'RemixOS 6.0' 583 | name: 'Remix OS' 584 | version: '2' 585 | 586 | - regex: 'RemixOS' 587 | name: 'Remix OS' 588 | version: '' 589 | 590 | 591 | ########## 592 | # Unix 593 | ########## 594 | - regex: '(?:SunOS|Solaris)(?:[/ ](\d+[\.\d]+))?' 595 | name: 'Solaris' 596 | version: '$1' 597 | 598 | 599 | - regex: 'AIX(?:[/ ]?(\d+[\.\d]+))?' 600 | name: 'AIX' 601 | version: '$1' 602 | 603 | 604 | - regex: 'HP-UX(?:[/ ]?(\d+[\.\d]+))?' 605 | name: 'HP-UX' 606 | version: '$1' 607 | 608 | 609 | - regex: 'FreeBSD(?:[/ ]?(\d+[\.\d]+))?' 610 | name: 'FreeBSD' 611 | version: '$1' 612 | 613 | 614 | - regex: 'NetBSD(?:[/ ]?(\d+[\.\d]+))?' 615 | name: 'NetBSD' 616 | version: '$1' 617 | 618 | 619 | - regex: 'OpenBSD(?:[/ ]?(\d+[\.\d]+))?' 620 | name: 'OpenBSD' 621 | version: '$1' 622 | 623 | 624 | - regex: 'DragonFly(?:[/ ]?(\d+[\.\d]+))?' 625 | name: 'DragonFly' 626 | version: '$1' 627 | 628 | 629 | - regex: 'Syllable(?:[/ ]?(\d+[\.\d]+))?' 630 | name: 'Syllable' 631 | version: '$1' 632 | 633 | 634 | - regex: 'IRIX(?:;64)?(?:[/ ]?(\d+[\.\d]+))' 635 | name: 'IRIX' 636 | version: '$1' 637 | 638 | 639 | - regex: 'OSF1(?:[/ ]?v?(\d+[\.\d]+))?' 640 | name: 'OSF1' 641 | version: '$1' 642 | 643 | 644 | 645 | ########## 646 | # Gaming Console 647 | ########## 648 | - regex: 'Nintendo Wii' 649 | name: 'Nintendo' 650 | version: 'Wii' 651 | 652 | 653 | - regex: 'PlayStation ?([3|4])' 654 | name: 'PlayStation' 655 | version: '$1' 656 | 657 | 658 | - regex: 'Xbox|KIN\.(?:One|Two)' 659 | name: 'Xbox' 660 | version: '360' 661 | 662 | 663 | 664 | ########## 665 | # Mobile Gaming Console 666 | ########## 667 | - regex: 'Nitro|Nintendo ([3]?DS[i]?)' 668 | name: 'Nintendo Mobile' 669 | version: '$1' 670 | 671 | 672 | - regex: 'PlayStation ((?:Portable|Vita))' 673 | name: 'PlayStation Portable' 674 | version: '$1' 675 | 676 | 677 | 678 | ########## 679 | # IBM 680 | ########## 681 | - regex: 'OS/2' 682 | name: 'OS/2' 683 | version: '' 684 | 685 | 686 | 687 | ########### 688 | # Linux (Generic) 689 | ########### 690 | - regex: 'Linux(?:OS)?[^a-z]' 691 | name: 'GNU/Linux' 692 | version: '' 693 | 694 | 695 | -------------------------------------------------------------------------------- /spec/fixtures/detector/feature_phone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | user_agent: AIRNESS-AIR99/REV 2.2.1/Teleca Q03B1 4 | os: [ ] 5 | client: 6 | type: browser 7 | name: Obigo 8 | short_name: OB 9 | version: 10 | engine: 11 | device: 12 | type: feature phone 13 | brand: AI 14 | model: AIR99 15 | os_family: Unknown 16 | browser_family: Unknown 17 | - 18 | user_agent: BenQ-CF61/1.00/WAP2.0/MIDP2.0/CLDC1.0 UP.Browser/6.3.0.4.c.1.102 (GUI) MMP/2.0 19 | os: [ ] 20 | client: 21 | type: browser 22 | name: Openwave Mobile Browser 23 | short_name: OV 24 | version: "6.3.0.4" 25 | engine: 26 | device: 27 | type: feature phone 28 | brand: BQ 29 | model: CF61 30 | os_family: Unknown 31 | browser_family: Unknown 32 | - 33 | user_agent: Cricket-A310/1.0 UP.Browser/6.3.0.7 (GUI) MMP/2.0 34 | os: [ ] 35 | client: 36 | type: browser 37 | name: Openwave Mobile Browser 38 | short_name: OV 39 | version: "6.3.0.7" 40 | engine: 41 | device: 42 | type: feature phone 43 | brand: CK 44 | model: A310 45 | os_family: Unknown 46 | browser_family: Unknown 47 | - 48 | user_agent: R380 2.0 WAP1.1 49 | os: [ ] 50 | client: null 51 | device: 52 | type: feature phone 53 | brand: EC 54 | model: R380 55 | os_family: Unknown 56 | browser_family: Unknown 57 | - 58 | user_agent: Fly_DS123/Q03C_MAUI_Browser/MIDP2.0 Configuration/CLDC-1.1 59 | os: [ ] 60 | client: null 61 | device: 62 | type: feature phone 63 | brand: FL 64 | model: DS123 65 | os_family: Unknown 66 | browser_family: Unknown 67 | - 68 | user_agent: FLY_E141TV_PLUS/ WAP Browser/MAUI(HTTP PGDL;HTTPS)Profile/Q03C1-2.40 ru-RU 69 | os: [ ] 70 | client: null 71 | device: 72 | type: feature phone 73 | brand: FL 74 | model: E141TV PLUS 75 | os_family: Unknown 76 | browser_family: Unknown 77 | - 78 | user_agent: Fly_E158/WAPBrowserProfile/MIDP2.0 Configuration/CLDC1.1 79 | os: [ ] 80 | client: null 81 | device: 82 | type: feature phone 83 | brand: FL 84 | model: E158 85 | os_family: Unknown 86 | browser_family: Unknown 87 | - 88 | user_agent: | 89 | GIONEE50_12864_11B_HW (MRE\\2.5.00(3072) resolution\\240320 chipset\\MT6250 touch\\1 tpannel\\0 camera\\1 gsensor\\0 keyboard\ 90 | ormal) 1307SY_0201_V1045 Release/2013.06.28 WAP Browser/MAUI (HTTP PGDL; HTTPS) Profile/Profile/MIDP-2.0 Configuration/CLDC-1.1 Q03C1-2.40 en-US 91 | os: [ ] 92 | client: null 93 | device: 94 | type: feature phone 95 | brand: GI 96 | model: 50 97 | os_family: Unknown 98 | browser_family: Unknown 99 | - 100 | user_agent: GIONEE S80/Q03C MAUI-browser/MIDP2.0/CLDC1.1/Screen-240X320 101 | os: [ ] 102 | client: null 103 | device: 104 | type: feature phone 105 | brand: GI 106 | model: S80 107 | os_family: Unknown 108 | browser_family: Unknown 109 | - 110 | user_agent: Karbonn K222s WAP-Browser/1.0.0 111 | os: [ ] 112 | client: null 113 | device: 114 | type: feature phone 115 | brand: KA 116 | model: K222s 117 | os_family: Unknown 118 | browser_family: Unknown 119 | - 120 | user_agent: Karbonn K595 WAP-Browser/1.0.0 121 | os: [ ] 122 | client: null 123 | device: 124 | type: feature phone 125 | brand: KA 126 | model: K595 127 | os_family: Unknown 128 | browser_family: Unknown 129 | - 130 | user_agent: WAP Browser-Karbonn K84/1.0.0 131 | os: [ ] 132 | client: null 133 | device: 134 | type: feature phone 135 | brand: KA 136 | model: K84 137 | os_family: Unknown 138 | browser_family: Unknown 139 | - 140 | user_agent: KDDI-CA3H UP.Browser/6.2_7.2.7.1.K.5.214 (GUI) MMP/2.0 141 | os: [ ] 142 | client: 143 | type: browser 144 | name: Openwave Mobile Browser 145 | short_name: OV 146 | version: "6.2" 147 | engine: 148 | device: 149 | type: feature phone 150 | brand: KD 151 | model: CA3H 152 | os_family: Unknown 153 | browser_family: Unknown 154 | - 155 | user_agent: Mozilla/5.0 Opera/9.80 (KDDI-KC4A; BREW; Opera Mobi; U; ja) Presto/2.4.18 Version/10.00 156 | os: 157 | name: Brew 158 | short_name: BMP 159 | version: 160 | platform: 161 | client: 162 | type: browser 163 | name: Opera Mobile 164 | short_name: OM 165 | version: "10.00" 166 | engine: Presto 167 | device: 168 | type: feature phone 169 | brand: KD 170 | model: KC4A 171 | os_family: Brew 172 | browser_family: Opera 173 | - 174 | user_agent: KDDI-SN3V UP.Browser/6.2_7.2.7.1.K.7.113 (GUI) MMP/2.0 175 | os: [ ] 176 | client: 177 | type: browser 178 | name: Openwave Mobile Browser 179 | short_name: OV 180 | version: "6.2" 181 | engine: 182 | device: 183 | type: feature phone 184 | brand: KD 185 | model: SN3V 186 | os_family: Unknown 187 | browser_family: Unknown 188 | - 189 | user_agent: KDDI-TS3W UP.Browser/6.2_7.2.7.1.K.6.1.102 (GUI) MMP/2.0 190 | os: [ ] 191 | client: 192 | type: browser 193 | name: Openwave Mobile Browser 194 | short_name: OV 195 | version: "6.2" 196 | engine: 197 | device: 198 | type: feature phone 199 | brand: KD 200 | model: TS3W 201 | os_family: Unknown 202 | browser_family: Unknown 203 | - 204 | user_agent: Mozilla/4.0 (Brew MP 1.0.4; U; en-us; Kyocera; NetFront/4.1/AMB) Sprint S2151-BST 205 | os: 206 | name: Brew 207 | short_name: BMP 208 | version: "1.0.4" 209 | platform: 210 | client: 211 | type: browser 212 | name: NetFront 213 | short_name: NF 214 | version: "4.1" 215 | engine: NetFront 216 | device: 217 | type: feature phone 218 | brand: KY 219 | model: Coast 220 | os_family: Brew 221 | browser_family: NetFront 222 | - 223 | user_agent: MOT-V360v/08.B7.58R MIB/2.2.1 Profile/MIDP-2.0 Configuration/CLDC-1.1 224 | os: [ ] 225 | client: null 226 | device: 227 | type: feature phone 228 | brand: MR 229 | model: V360 230 | os_family: Unknown 231 | browser_family: Unknown 232 | - 233 | user_agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 6.12; es-US; KIN.Two 1.0) 234 | os: 235 | name: Windows CE 236 | short_name: WCE 237 | version: 238 | platform: 239 | client: 240 | type: browser 241 | name: IE Mobile 242 | short_name: IM 243 | version: "6.12" 244 | engine: Trident 245 | device: 246 | type: feature phone 247 | brand: MS 248 | model: Kin Two 249 | os_family: Windows Mobile 250 | browser_family: Internet Explorer 251 | - 252 | user_agent: Mozilla/4.0 (jig browser 7.3.7; P902i) 253 | os: [ ] 254 | client: 255 | type: browser 256 | name: Jig Browser 257 | short_name: JI 258 | version: "7.3.7" 259 | engine: 260 | device: 261 | type: feature phone 262 | brand: PA 263 | model: P902i 264 | os_family: Unknown 265 | browser_family: Unknown 266 | - 267 | user_agent: SAMSUNG-GT-E2152/E2152XXJK2 NetFront/3.5 Profile/MIDP-2.0 Configuration/CLDC-1.1 268 | os: [ ] 269 | client: 270 | type: browser 271 | name: NetFront 272 | short_name: NF 273 | version: "3.5" 274 | engine: NetFront 275 | device: 276 | type: feature phone 277 | brand: SA 278 | model: E2152 279 | os_family: Unknown 280 | browser_family: NetFront 281 | - 282 | user_agent: SonyEricssonU10/R1x Browser/NetFront/3.5 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.5 283 | os: [ ] 284 | client: 285 | type: browser 286 | name: NetFront 287 | short_name: NF 288 | version: "3.5" 289 | engine: NetFront 290 | device: 291 | type: feature phone 292 | brand: SE 293 | model: Aino 294 | os_family: Unknown 295 | browser_family: NetFront 296 | - 297 | user_agent: SonyEricssonU100i/R1x Browser/NetFront/3.5 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.5 298 | os: [ ] 299 | client: 300 | type: browser 301 | name: NetFront 302 | short_name: NF 303 | version: "3.5" 304 | engine: NetFront 305 | device: 306 | type: feature phone 307 | brand: SE 308 | model: Aino 309 | os_family: Unknown 310 | browser_family: NetFront 311 | - 312 | user_agent: SonyEricssonJ108i/R1x Browser/NetFront/3.5 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.5 313 | os: [ ] 314 | client: 315 | type: browser 316 | name: NetFront 317 | short_name: NF 318 | version: "3.5" 319 | engine: NetFront 320 | device: 321 | type: feature phone 322 | brand: SE 323 | model: Cedar 324 | os_family: Unknown 325 | browser_family: NetFront 326 | - 327 | user_agent: SonyEricssonJ10i2/R1x Browser/NetFront/3.5 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.5 328 | os: [ ] 329 | client: 330 | type: browser 331 | name: NetFront 332 | short_name: NF 333 | version: "3.5" 334 | engine: NetFront 335 | device: 336 | type: feature phone 337 | brand: SE 338 | model: Elm 339 | os_family: Unknown 340 | browser_family: NetFront 341 | - 342 | user_agent: SonyEricssonJ20i/R1x Browser/NetFront/3.5 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.5 343 | os: [ ] 344 | client: 345 | type: browser 346 | name: NetFront 347 | short_name: NF 348 | version: "3.5" 349 | engine: NetFront 350 | device: 351 | type: feature phone 352 | brand: SE 353 | model: Hazel 354 | os_family: Unknown 355 | browser_family: NetFront 356 | - 357 | user_agent: SonyEricssonF100i/R1x Browser/NetFront/3.4 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.4 358 | os: [ ] 359 | client: 360 | type: browser 361 | name: NetFront 362 | short_name: NF 363 | version: "3.4" 364 | engine: NetFront 365 | device: 366 | type: feature phone 367 | brand: SE 368 | model: Jalou 369 | os_family: Unknown 370 | browser_family: NetFront 371 | - 372 | user_agent: SonyEricssonWT13i/R3AF010 TelecaBrowser/Q07C1-1 Profile/MIDP-2.0 Configuration/CLDC-1.1 373 | os: [ ] 374 | client: 375 | type: browser 376 | name: Obigo 377 | short_name: OB 378 | version: 379 | engine: 380 | device: 381 | type: feature phone 382 | brand: SE 383 | model: Mix Walkman 384 | os_family: Unknown 385 | browser_family: Unknown 386 | - 387 | user_agent: UCWEB/2.0 (Java; U; MIDP-2.0; fr-FR; sonyericssonwt13i) U2/1.0.0 UCBrowser/9.2.0.311 U2/1.0.0 Mobile UNTRUSTED/1.0 388 | os: [ ] 389 | client: 390 | type: browser 391 | name: UC Browser 392 | short_name: UC 393 | version: "9.2.0.311" 394 | engine: 395 | device: 396 | type: feature phone 397 | brand: SE 398 | model: Mix Walkman 399 | os_family: Unknown 400 | browser_family: Unknown 401 | - 402 | user_agent: SonyEricssonJ105i/R1x Browser/NetFront/3.4 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.4 403 | os: [ ] 404 | client: 405 | type: browser 406 | name: NetFront 407 | short_name: NF 408 | version: "3.4" 409 | engine: NetFront 410 | device: 411 | type: feature phone 412 | brand: SE 413 | model: Naite 414 | os_family: Unknown 415 | browser_family: NetFront 416 | - 417 | user_agent: SonyEricssonP910i/R3A SEMC-Browser/Symbian/3.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 418 | os: 419 | name: Symbian^3 420 | short_name: SY3 421 | version: 422 | platform: 423 | client: 424 | type: browser 425 | name: SEMC-Browser 426 | short_name: SC 427 | version: 428 | engine: 429 | device: 430 | type: feature phone 431 | brand: SE 432 | model: P910i 433 | os_family: Symbian 434 | browser_family: Unknown 435 | - 436 | user_agent: Mozilla/5.0 (SymbianOS/9.2;U; Series60/5.0 SonyEricssonU1i/1.00;Profile/MIDP-2.1 Configuration/ CLDC-1.1)AppleWebKit/525 (KHTML, like Gecko) version/3.0Safari/525 437 | os: 438 | name: Symbian OS Series 60 439 | short_name: S60 440 | version: "5.0" 441 | platform: 442 | client: 443 | type: browser 444 | name: Nokia Browser 445 | short_name: NB 446 | version: "7.0" 447 | engine: WebKit 448 | device: 449 | type: feature phone 450 | brand: SE 451 | model: Satio 452 | os_family: Symbian 453 | browser_family: Nokia Browser 454 | - 455 | user_agent: SonyEricssonU1i/R1CA; Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 Safari/525 456 | os: 457 | name: Symbian OS Series 60 458 | short_name: S60 459 | version: "5.0" 460 | platform: 461 | client: 462 | type: browser 463 | name: Nokia Browser 464 | short_name: NB 465 | version: "7.0" 466 | engine: WebKit 467 | device: 468 | type: feature phone 469 | brand: SE 470 | model: Satio 471 | os_family: Symbian 472 | browser_family: Nokia Browser 473 | - 474 | user_agent: SonyEricssonW100i/1.0 Browser/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 475 | os: [ ] 476 | client: null 477 | device: 478 | type: feature phone 479 | brand: SE 480 | model: Spiro 481 | os_family: Unknown 482 | browser_family: Unknown 483 | - 484 | user_agent: SonyEricssonCK13i/R5AA032 TelecaBrowser/Q07C1-1 Profile/MIDP-2.0 Configuration/CLDC-1.1 485 | os: [ ] 486 | client: 487 | type: browser 488 | name: Obigo 489 | short_name: OB 490 | version: 491 | engine: 492 | device: 493 | type: feature phone 494 | brand: SE 495 | model: txt 496 | os_family: Unknown 497 | browser_family: Unknown 498 | - 499 | user_agent: SonyEricssonCK15i/R3AE021 TelecaBrowser/Q07C1-1 Profile/MIDP-2.0 Configuration/CLDC-1.1 500 | os: [ ] 501 | client: 502 | type: browser 503 | name: Obigo 504 | short_name: OB 505 | version: 506 | engine: 507 | device: 508 | type: feature phone 509 | brand: SE 510 | model: txt pro 511 | os_family: Unknown 512 | browser_family: Unknown 513 | - 514 | user_agent: UCWEB/2.0 (Java; U; MIDP-2.0; es-LA; SonyEricssonCK15i) U2/1.0.0 UCBrowser/9.4.0.342 U2/1.0.0 Mobile UNTRUSTED/1.0 515 | os: [ ] 516 | client: 517 | type: browser 518 | name: UC Browser 519 | short_name: UC 520 | version: "9.4.0.342" 521 | engine: 522 | device: 523 | type: feature phone 524 | brand: SE 525 | model: txt pro 526 | os_family: Unknown 527 | browser_family: Unknown 528 | - 529 | user_agent: Mozilla/5.0 (SymbianOS/9.2;U; Series60/5.0 SonyEricssonU5i/1.00;Profile/MIDP-2.1 Configuration/ CLDC-1.1)AppleWebKit/525 (KHTML, like Gecko) version/3.0Safari/525 530 | os: 531 | name: Symbian OS Series 60 532 | short_name: S60 533 | version: "5.0" 534 | platform: 535 | client: 536 | type: browser 537 | name: Nokia Browser 538 | short_name: NB 539 | version: "7.0" 540 | engine: WebKit 541 | device: 542 | type: feature phone 543 | brand: SE 544 | model: Vivaz 545 | os_family: Symbian 546 | browser_family: Nokia Browser 547 | - 548 | user_agent: Mozilla/5.0 (SymbianOS/9.2;U; Series60/5.0 SonyEricssonU8i/1.00;Profile/MIDP-2.1 Configuration/ CLDC-1.1)AppleWebKit/525 (KHTML, like Gecko) version/3.0Safari/525 549 | os: 550 | name: Symbian OS Series 60 551 | short_name: S60 552 | version: "5.0" 553 | platform: 554 | client: 555 | type: browser 556 | name: Nokia Browser 557 | short_name: NB 558 | version: "7.0" 559 | engine: WebKit 560 | device: 561 | type: feature phone 562 | brand: SE 563 | model: Vivaz pro 564 | os_family: Symbian 565 | browser_family: Nokia Browser 566 | - 567 | user_agent: SonyEricssonW150a/1.0 TelecaBrowser/Q07C1-3 Profile/MIDP-2.0 Configuration/CLDC-1.1 568 | os: [ ] 569 | client: 570 | type: browser 571 | name: Obigo 572 | short_name: OB 573 | version: 574 | engine: 575 | device: 576 | type: feature phone 577 | brand: SE 578 | model: Yendo 579 | os_family: Unknown 580 | browser_family: Unknown 581 | - 582 | user_agent: SonyEricssonW20/R1x Browser/NetFront/3.5 Profile/MIDP-2.1 Configuration/CLDC-1.1 JavaPlatform/JP-8.5 583 | os: [ ] 584 | client: 585 | type: browser 586 | name: NetFront 587 | short_name: NF 588 | version: "3.5" 589 | engine: NetFront 590 | device: 591 | type: feature phone 592 | brand: SE 593 | model: Zylo 594 | os_family: Unknown 595 | browser_family: NetFront 596 | - 597 | user_agent: SAGEM-my411C-orange/1.0/ MIDP-2.0 Configuration/CLDC-1.1 Browser/UP.Browser/7.2.6.c.1.382 (GUI) 598 | os: [ ] 599 | client: 600 | type: browser 601 | name: Openwave Mobile Browser 602 | short_name: OV 603 | version: "7.2.6" 604 | engine: 605 | device: 606 | type: feature phone 607 | brand: SG 608 | model: my411C-orange 609 | os_family: Unknown 610 | browser_family: Unknown 611 | - 612 | user_agent: Sagem-my411X/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 Browser/UP.Browser/7.2.6.c.1.326 (GUI) 613 | os: [ ] 614 | client: 615 | type: browser 616 | name: Openwave Mobile Browser 617 | short_name: OV 618 | version: "7.2.6" 619 | engine: 620 | device: 621 | type: feature phone 622 | brand: SG 623 | model: my411X 624 | os_family: Unknown 625 | browser_family: Unknown 626 | - 627 | user_agent: SAGEM-my511X-orange/1.0/ MIDP-2.0 Configuration/CLDC-1.1 Browser/UP.Browser/7.2.6.c.1.393 (GUI) 628 | os: [ ] 629 | client: 630 | type: browser 631 | name: Openwave Mobile Browser 632 | short_name: OV 633 | version: "7.2.6" 634 | engine: 635 | device: 636 | type: feature phone 637 | brand: SG 638 | model: my511X-orange 639 | os_family: Unknown 640 | browser_family: Unknown 641 | - 642 | user_agent: SAGEM-myC5-2v/1.0 UP.Browser/6.2.3.3.g.2.106 (GUI) MMP/2.0 643 | os: [ ] 644 | client: 645 | type: browser 646 | name: Openwave Mobile Browser 647 | short_name: OV 648 | version: "6.2.3.3" 649 | engine: 650 | device: 651 | type: feature phone 652 | brand: SG 653 | model: myC5-2v 654 | os_family: Unknown 655 | browser_family: Unknown 656 | - 657 | user_agent: SAGEM-myV-55/2.0 Profile/MIDP-2.0 Configuration/CLDC-1.0 UP.Browser/6.2.2.6.d.3.100 (GUI) MMP/1.0 658 | os: [ ] 659 | client: 660 | type: browser 661 | name: Openwave Mobile Browser 662 | short_name: OV 663 | version: "6.2.2.6" 664 | engine: 665 | device: 666 | type: feature phone 667 | brand: SG 668 | model: myV-55 669 | os_family: Unknown 670 | browser_family: Unknown 671 | - 672 | user_agent: Mozilla/4.0 (BREW 3.1.5; U; en-us; Sanyo; NetFront/3.5.1/AMB) Boost SCP6760 673 | os: 674 | name: Brew 675 | short_name: BMP 676 | version: "3.1.5" 677 | platform: 678 | client: 679 | type: browser 680 | name: NetFront 681 | short_name: NF 682 | version: "3.5.1" 683 | engine: NetFront 684 | device: 685 | type: feature phone 686 | brand: SY 687 | model: Incognito 688 | os_family: Brew 689 | browser_family: NetFront 690 | - 691 | user_agent: Mozilla/4.0 (Brew MP 1.0.2; U; en-us; Sanyo; NetFront/3.5.1/AMB) Boost SCP6780 692 | os: 693 | name: Brew 694 | short_name: BMP 695 | version: "1.0.2" 696 | platform: 697 | client: 698 | type: browser 699 | name: NetFront 700 | short_name: NF 701 | version: "3.5.1" 702 | engine: NetFront 703 | device: 704 | type: feature phone 705 | brand: SY 706 | model: Innuendo 707 | os_family: Brew 708 | browser_family: NetFront 709 | - 710 | user_agent: Mozilla/4.0 (REX; U; en-us; Sanyo; SCP-6750/US; NetFront/3.4/AMB) 711 | os: [ ] 712 | client: 713 | type: browser 714 | name: NetFront 715 | short_name: NF 716 | version: "3.4" 717 | engine: NetFront 718 | device: 719 | type: feature phone 720 | brand: SY 721 | model: Katana Eclipse X 722 | os_family: Unknown 723 | browser_family: NetFront 724 | - 725 | user_agent: Mozilla/4.0 (MobilePhone PM-8200/US/1.0) NetFront/3.x MMP/2.0 726 | os: [ ] 727 | client: 728 | type: browser 729 | name: NetFront 730 | short_name: NF 731 | version: "3" 732 | engine: NetFront 733 | device: 734 | type: feature phone 735 | brand: SY 736 | model: PM-8200 737 | os_family: Unknown 738 | browser_family: NetFront 739 | - 740 | user_agent: TIANYU-KTOUCH/A930/Screen-240X320 741 | os: [ ] 742 | client: null 743 | device: 744 | type: feature phone 745 | brand: TI 746 | model: A930 747 | os_family: Unknown 748 | browser_family: Unknown 749 | - 750 | user_agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 8.12; MSIEMobile 6.0) 320x240; VZW; UTStar-XV6175; Window Mobile 6.1 Standard; 751 | os: 752 | name: Windows CE 753 | short_name: WCE 754 | version: 755 | platform: 756 | client: 757 | type: browser 758 | name: IE Mobile 759 | short_name: IM 760 | version: "8.12" 761 | engine: Trident 762 | device: 763 | type: feature phone 764 | brand: UT 765 | model: XV6175 766 | os_family: Windows Mobile 767 | browser_family: Internet Explorer 768 | - 769 | user_agent: vk-vk900/1.1 up.browser/6.2.3.4 (gui) mmp/2.0 770 | os: [ ] 771 | client: 772 | type: browser 773 | name: Openwave Mobile Browser 774 | short_name: OV 775 | version: "6.2.3.4" 776 | engine: 777 | device: 778 | type: feature phone 779 | brand: VK 780 | model: vk900 781 | os_family: Unknown 782 | browser_family: Unknown 783 | -------------------------------------------------------------------------------- /regexes/client/browsers.yml: -------------------------------------------------------------------------------- 1 | ############### 2 | # Device Detector - The Universal Device Detection library for parsing User Agents 3 | # 4 | # @link http://piwik.org 5 | # @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 6 | ############### 7 | 8 | # Microsoft Edge (newer versions of IE) 9 | - regex: 'Edge[ /](\d+[\.\d]+)' 10 | name: 'Microsoft Edge' 11 | version: '$1' 12 | engine: 13 | default: 'Edge' 14 | 15 | # 360 Browser 16 | - regex: 'QIHU 360[ES]E' 17 | name: '360 Browser' 18 | version: '' 19 | 20 | # 360 Phone Browser 21 | - regex: '360 Aphone Browser(?: \((\d+[\.\d]+)(?:beta)?\))?' 22 | name: '360 Phone Browser' 23 | version: '$1' 24 | engine: 25 | default: 'WebKit' 26 | 27 | #SailfishBrowser 28 | - regex: 'SailfishBrowser(?:/(\d+[\.\d]+))?' 29 | name: 'Sailfish Browser' 30 | version: '$1' 31 | engine: 32 | default: 'Gecko' 33 | 34 | # SeaMonkey 35 | - regex: '(Iceape|SeaMonkey|gnuzilla)(?:/(\d+[\.\d]+))?' 36 | name: '$1' 37 | version: '$2' 38 | engine: 39 | default: 'Gecko' 40 | 41 | # Camino 42 | - regex: 'Camino(?:/(\d+[\.\d]+))?' 43 | name: 'Camino' 44 | version: '$1' 45 | engine: 46 | default: 'Gecko' 47 | 48 | #Fennec (Firefox for mobile) 49 | - regex: 'Fennec(?:/(\d+[\.\d]+))?' 50 | name: 'Fennec' 51 | version: '$1' 52 | engine: 53 | default: 'Gecko' 54 | 55 | #MicroB 56 | - regex: 'Firefox.*Tablet browser (\d+[\.\d]+)' 57 | name: 'MicroB' 58 | version: '$1' 59 | engine: 60 | default: 'Gecko' 61 | - regex: 'Maemo Browser(?: (\d+[\.\d]+))?' 62 | name: 'MicroB' 63 | version: '$1' 64 | engine: 65 | default: 'Gecko' 66 | 67 | #Deepnet Explorer 68 | - regex: 'Deepnet Explorer (\d+[\.\d]+)?' 69 | name: 'Deepnet Explorer' 70 | version: '$1' 71 | 72 | 73 | #Avant Browser 74 | - regex: 'Avant Browser' 75 | name: 'Avant Browser' 76 | version: '' 77 | engine: 78 | default: '' # multiple 79 | 80 | #Amigo 81 | - regex: 'Chrome/(\d+[\.\d]+).*MRCHROME' 82 | name: 'Amigo' 83 | version: '$1' 84 | engine: 85 | default: 'WebKit' 86 | versions: 87 | 28: 'Blink' 88 | 89 | #Atomic Web Browser 90 | - regex: 'AtomicBrowser(?:/(\d+[\.\d]+))?' 91 | name: 'Atomic Web Browser' 92 | version: '$1' 93 | 94 | #Bunjalloo 95 | - regex: 'Bunjalloo(?:/(\d+[\.\d]+))?' 96 | name: 'Bunjalloo' 97 | version: '$1' 98 | 99 | #Brave 100 | - regex: 'Brave(?:/(\d+[\.\d]+))?' 101 | name: 'Brave' 102 | version: '$1' 103 | engine: 104 | default: 'Blink' 105 | 106 | #Iceweasel 107 | - regex: 'Iceweasel(?:/(\d+[\.\d]+))?' 108 | name: 'Iceweasel' 109 | version: '$1' 110 | engine: 111 | default: 'Gecko' 112 | 113 | #WebPositive 114 | - regex: 'WebPositive' 115 | name: 'WebPositive' 116 | version: '' 117 | engine: 118 | default: 'WebKit' 119 | 120 | 121 | #Pale Moon 122 | - regex: 'PaleMoon(?:/(\d+[\.\d]+))?' 123 | name: 'Pale Moon' 124 | version: '$1' 125 | engine: 126 | default: 'Gecko' 127 | 128 | #CometBird 129 | - regex: 'CometBird(?:/(\d+[\.\d]+))?' 130 | name: 'CometBird' 131 | version: '$1' 132 | engine: 133 | default: 'Gecko' 134 | 135 | #IceDragon 136 | - regex: 'IceDragon(?:/(\d+[\.\d]+))?' 137 | name: 'IceDragon' 138 | version: '$1' 139 | engine: 140 | default: 'Gecko' 141 | 142 | #Flock 143 | - regex: 'Flock(?:/(\d+[\.\d]+))?' 144 | name: 'Flock' 145 | version: '$1' 146 | engine: 147 | default: 'Gecko' 148 | versions: 149 | 3: 'WebKit' 150 | 151 | #Jig Browser 152 | - regex: 'jig browser(?: web;|9i?)?(?:[/ ](\d+[\.\d]+))?' 153 | name: 'Jig Browser' 154 | version: '$1' 155 | 156 | #Kapiko 157 | - regex: 'Kapiko(?:/(\d+[\.\d]+))?' 158 | name: 'Kapiko' 159 | version: '$1' 160 | engine: 161 | default: 'Gecko' 162 | 163 | #Kylo 164 | - regex: 'Kylo(?:/(\d+[\.\d]+))?' 165 | name: 'Kylo' 166 | version: '$1' 167 | engine: 168 | default: 'Gecko' 169 | 170 | #Swiftfox 171 | - regex: 'Firefox/(\d+[\.\d]+).*\(Swiftfox\)' 172 | name: 'Swiftfox' 173 | version: '$1' 174 | engine: 175 | default: 'Gecko' 176 | 177 | #Firefox 178 | - regex: 'Firefox(?:/(\d+[\.\d]+))?' 179 | name: 'Firefox' 180 | version: '$1' 181 | engine: 182 | default: 'Gecko' 183 | - regex: '(BonEcho|GranParadiso|Lorentz|Minefield|Namoroka|Shiretoko)/(\d+[\.\d]+)' 184 | name: 'Firefox' 185 | version: '$1 ($2)' 186 | engine: 187 | default: 'Gecko' 188 | - regex: 'FxiOS/(\d+[\.\d]+)' 189 | name: 'Firefox' 190 | version: 'iOS $1' 191 | engine: 192 | default: 'WebKit' 193 | 194 | #ANT Fresco 195 | - regex: 'ANTFresco(?:[/ ](\d+[\.\d]+))?' 196 | name: 'ANT Fresco' 197 | version: '$1' 198 | 199 | #ANTGalio 200 | - regex: 'ANTGalio(?:/(\d+[\.\d]+))?' 201 | name: 'ANTGalio' 202 | version: '$1' 203 | 204 | #Espial TV Browser 205 | - regex: '(?:Espial|Escape)(?:[/ ](\d+[\.\d]+))?' 206 | name: 'Espial TV Browser' 207 | version: '$1' 208 | 209 | #RockMelt 210 | - regex: 'RockMelt(?:/(\d+[\.\d]+))?' 211 | name: 'RockMelt' 212 | version: '$1' 213 | engine: 214 | default: 'WebKit' 215 | 216 | #Fireweb Navigator 217 | - regex: 'Fireweb Navigator(?:/(\d+[\.\d]+))?' 218 | name: 'Fireweb Navigator' 219 | version: '$1' 220 | 221 | #Fireweb 222 | - regex: 'Fireweb(?:/(\d+[\.\d]+))?' 223 | name: 'Fireweb' 224 | version: '$1' 225 | 226 | #Netscape 227 | - regex: '(?:Navigator|Netscape6?)(?:/(\d+[\.\d]+))?' 228 | name: 'Netscape' 229 | version: '$1' 230 | engine: 231 | default: '' # Mosaic in the first versions, then Gecko 232 | 233 | #Opera 234 | - regex: '(?:Opera Tablet.*Version|Opera/.+Opera Mobi.+Version|Mobile.+OPR)/(\d+[\.\d]+)' 235 | name: 'Opera Mobile' 236 | version: '$1' 237 | engine: 238 | default: 'Presto' 239 | versions: 240 | 15: 'Blink' 241 | - regex: 'Opera Mini/(?:att/)?(\d+[\.\d]+)' 242 | name: 'Opera Mini' 243 | version: '$1' 244 | engine: 245 | default: 'Presto' 246 | - regex: 'Opera.+Edition Next.+Version/(\d+[\.\d]+)' 247 | name: 'Opera Next' 248 | version: '$1' 249 | engine: 250 | default: 'Presto' 251 | versions: 252 | 15: 'Blink' 253 | - regex: '(?:Opera|OPR)[/ ](?:9.80.*Version/)?(\d+[\.\d]+).+Edition Next' 254 | name: 'Opera Next' 255 | version: '$1' 256 | engine: 257 | default: 'Presto' 258 | versions: 259 | 15: 'Blink' 260 | - regex: '(?:Opera|OPR)[/ ]?(?:9.80.*Version/)?(\d+[\.\d]+)' 261 | name: 'Opera' 262 | version: '$1' 263 | engine: 264 | default: '' 265 | versions: 266 | 3.5: 'Elektra' 267 | 7: 'Presto' 268 | 15: 'Blink' 269 | 270 | #Rekonq 271 | - regex: 'rekonq(?:/(\d+[\.\d]+))?' 272 | name: 'Rekonq' 273 | version: '$1' 274 | engine: 275 | default: 'WebKit' 276 | 277 | #CoolNovo (former ChromePlus) 278 | - regex: 'CoolNovo(?:/(\d+[\.\d]+))?' 279 | name: 'CoolNovo' 280 | version: '$1' 281 | engine: 282 | default: '' # multi engine 283 | 284 | #Comodo Dragon 285 | - regex: 'Comodo[ _]Dragon(?:/(\d+[\.\d]+))?' 286 | name: 'Comodo Dragon' 287 | version: '$1' 288 | engine: 289 | default: 'WebKit' 290 | versions: 291 | 28: 'Blink' 292 | 293 | #ChromePlus 294 | - regex: 'ChromePlus(?:/(\d+[\.\d]+))?' 295 | name: 'ChromePlus' 296 | version: '$1' 297 | engine: 298 | default: '' # multi engine 299 | 300 | #Conkeror 301 | - regex: 'Conkeror(?:/(\d+[\.\d]+))?' 302 | name: 'Conkeror' 303 | version: '$1' 304 | engine: 305 | default: 'Gecko' 306 | 307 | #Konqueror 308 | - regex: 'Konqueror(?:/(\d+[\.\d]+))?' 309 | name: 'Konqueror' 310 | version: '$1' 311 | engine: 312 | default: 'KHTML' 313 | versions: 314 | 4: '' # multiple (KHTML or WebKit) 315 | 316 | #Baidu Browser 317 | - regex: 'baidubrowser(?:[/ ](\d+[\.\d]*))?' 318 | name: 'Baidu Browser' 319 | version: '$1' 320 | 321 | #Baidu Spark 322 | - regex: '(?:(?:BD)?Spark|BIDUBrowser)[/ ](\d+[\.\d]*)' 323 | name: 'Baidu Spark' 324 | version: '$1' 325 | 326 | #Yandex Browser 327 | - regex: 'YaBrowser(?:/(\d+[\.\d]*))?' 328 | name: 'Yandex Browser' 329 | version: '$1' 330 | engine: 331 | default: 'Blink' 332 | 333 | #Vivaldi 334 | - regex: 'Vivaldi(?:/(\d+[\.\d]+))?' 335 | name: 'Vivaldi' 336 | version: '$1' 337 | engine: 338 | default: 'Blink' 339 | 340 | #TweakStyle 341 | - regex: 'TweakStyle(?:/(\d+[\.\d]+))?' 342 | name: 'TweakStyle' 343 | version: '$1' 344 | engine: 345 | default: 'Blink' 346 | 347 | #Midori 348 | - regex: 'Midori(?:/(\d+[\.\d]+))?' 349 | name: 'Midori' 350 | version: '$1' 351 | engine: 352 | default: 'WebKit' 353 | 354 | #Mercury 355 | - regex: 'Mercury(?:/(\d+[\.\d]+))?' 356 | name: 'Mercury' 357 | version: '$1' 358 | 359 | #Maxthon 360 | - regex: '(?:Maxthon|MxBrowser)[ /](\d+[\.\d]+)' 361 | name: 'Maxthon' 362 | version: '$1' 363 | engine: 364 | default: '' # Trident and WebKit 365 | versions: 366 | 3: 'WebKit' 367 | 368 | - regex: '(?:Maxthon|MyIE2|Uzbl)' 369 | name: 'Maxthon' 370 | version: '' 371 | engine: 372 | default: '' # Trident and WebKit 373 | 374 | #Puffin 375 | - regex: 'Puffin(?:/(\d+[\.\d]+))?' 376 | name: 'Puffin' 377 | version: '$1' 378 | 379 | #Iron 380 | - regex: 'Iron(?:/(\d+[\.\d]+))?' 381 | name: 'Iron' 382 | version: '$1' 383 | engine: 384 | default: 'WebKit' 385 | versions: 386 | 28: 'Blink' 387 | 388 | #Epiphany 389 | - regex: 'Epiphany(?:/(\d+[\.\d]+))?' 390 | name: 'Epiphany' 391 | version: '$1' 392 | engine: 393 | default: 'Gecko' 394 | versions: 395 | 2.9.16: '' # multi engine 396 | 2.28: 'WebKit' 397 | 398 | # Liebao 399 | - regex: 'LBBrowser(?:[ /](\d+[\.\d]+))?' 400 | name: 'Liebao' 401 | version: '$1' 402 | 403 | # Sogou Explorer 404 | - regex: 'SE (\d+[\.\d]+)' 405 | name: 'Sogou Explorer' 406 | version: '$1' 407 | 408 | # QQ Browser 409 | - regex: 'M?QQBrowser(?:/(?:Mini)?([\.\d]+))?' 410 | name: 'QQ Browser' 411 | version: '$1' 412 | 413 | # MIUI Browser 414 | - regex: 'MIUIBrowser(?:/(\d+[\.\d]+))?' 415 | name: 'MIUI Browser' 416 | version: '$1' 417 | 418 | # Coc Coc 419 | # This browser (http://coccoc.vn/) is built on top of Chromium with 420 | # additional features for Vietnamese users. Its regex has to be placed 421 | # before generic Chrome regex, or Chrome regex will match first and 422 | # the browser is mistaken as "Chrome". 423 | - regex: 'coc_coc_browser(?:/(\d+[\.\d]+))?' 424 | name: 'Coc Coc' 425 | version: '$1' 426 | engine: 427 | default: 'WebKit' 428 | versions: 429 | 28: 'Blink' 430 | 431 | #Samsung Browser 432 | - regex: 'Samsung ?Browser(?:[/ ](\d+[\.\d]+))?' 433 | name: 'Samsung Browser' 434 | version: '$1' 435 | 436 | #Chrome 437 | - regex: 'CrMo(?:/(\d+[\.\d]+))?' 438 | name: 'Chrome Mobile' 439 | version: '$1' 440 | engine: 441 | default: 'WebKit' 442 | versions: 443 | 28: 'Blink' 444 | - regex: 'CriOS(?:/(\d+[\.\d]+))?' 445 | name: 'Chrome Mobile iOS' 446 | version: '$1' 447 | engine: 448 | default: 'WebKit' 449 | - regex: 'Chrome(?:/(\d+[\.\d]+))? Mobile' 450 | name: 'Chrome Mobile' 451 | version: '$1' 452 | engine: 453 | default: 'WebKit' 454 | versions: 455 | 28: 'Blink' 456 | - regex: 'chromeframe(?:/(\d+[\.\d]+))?' 457 | name: 'Chrome Frame' 458 | version: '$1' 459 | engine: 460 | default: 'WebKit' 461 | - regex: 'Chromium(?:/(\d+[\.\d]+))?' 462 | name: 'Chromium' 463 | version: '$1' 464 | engine: 465 | default: 'WebKit' 466 | versions: 467 | 28: 'Blink' 468 | - regex: 'Chrome(?:/(\d+[\.\d]+))?' 469 | name: 'Chrome' 470 | version: '$1' 471 | engine: 472 | default: 'WebKit' 473 | versions: 474 | 28: 'Blink' 475 | 476 | #UC Browser 477 | - regex: 'UC[ ]?Browser(?:[ /]?(\d+[\.\d]+))?' 478 | name: 'UC Browser' 479 | version: '$1' 480 | - regex: 'UCWEB(?:[ /]?(\d+[\.\d]+))?' 481 | name: 'UC Browser' 482 | version: '$1' 483 | 484 | #Tizen Browser 485 | - regex: '(?:Tizen|SLP) Browser(?:/(\d+[\.\d]+))?' 486 | name: 'Tizen Browser' 487 | version: '$1' 488 | 489 | #Palm Blazer 490 | - regex: 'Blazer(?:/(\d+[\.\d]+))?' 491 | name: 'Palm Blazer' 492 | version: '$1' 493 | - regex: 'Pre/(\d+[\.\d]+)' 494 | name: 'Palm Pre' 495 | version: '$1' 496 | 497 | #wOSBrowser 498 | - regex: '(?:hpw|web)OS/(\d+[\.\d]+)' 499 | name: 'wOSBrowser' 500 | version: '$1' 501 | 502 | #Palm WebPro 503 | - regex: 'WebPro(?:[ /](\d+[\.\d]+))?' 504 | name: 'Palm WebPro' 505 | version: '$1' 506 | 507 | #Palmscape 508 | - regex: 'Palmscape(?:[ /](\d+[\.\d]+))?' 509 | name: 'Palmscape' 510 | version: '$1' 511 | 512 | #Jasmine 513 | - regex: 'Jasmine(?:[ /](\d+[\.\d]+))?' 514 | name: 'Jasmine' 515 | version: '$1' 516 | 517 | #Lynx 518 | - regex: 'Lynx(?:/(\d+[\.\d]+))?' 519 | name: 'Lynx' 520 | version: '$1' 521 | engine: 522 | default: 'Text-based' 523 | 524 | #NCSA Mosaic 525 | - regex: 'NCSA_Mosaic(?:/(\d+[\.\d]+))?' 526 | name: 'NCSA Mosaic' 527 | version: '$1' 528 | 529 | #ABrowse 530 | - regex: 'ABrowse(?: (\d+[\.\d]+))?' 531 | name: 'ABrowse' 532 | version: '$1' 533 | 534 | #Amaya 535 | - regex: 'amaya(?:/(\d+[\.\d]+))?' 536 | name: 'Amaya' 537 | version: '$1' 538 | 539 | #Amiga Voyager 540 | - regex: 'AmigaVoyager(?:/(\d+[\.\d]+))?' 541 | name: 'Amiga Voyager' 542 | version: '$1' 543 | 544 | #Amiga Aweb 545 | - regex: 'Amiga-Aweb(?:/(\d+[\.\d]+))?' 546 | name: 'Amiga Aweb' 547 | version: '$1' 548 | 549 | #Arora 550 | - regex: 'Arora(?:/(\d+[\.\d]+))?' 551 | name: 'Arora' 552 | version: '$1' 553 | engine: 554 | default: 'WebKit' 555 | 556 | #Beonex 557 | - regex: 'Beonex(?:/(\d+[\.\d]+))?' 558 | name: 'Beonex' 559 | version: '$1' 560 | engine: 561 | default: 'Gecko' 562 | 563 | #BrowseX 564 | - regex: 'BrowseX \((\d+[\.\d]+)' 565 | name: 'BrowseX' 566 | version: '$1' 567 | 568 | #Charon 569 | - regex: 'Charon(?:[/ ](\d+[\.\d]+))?' 570 | name: 'Charon' 571 | version: '$1' 572 | 573 | #Cheshire 574 | - regex: 'Cheshire(?:/(\d+[\.\d]+))?' 575 | name: 'Cheshire' 576 | version: '$1' 577 | 578 | #Dillo 579 | - regex: 'Dillo(?:/(\d+[\.\d]+))?' 580 | name: 'Dillo' 581 | version: '$1' 582 | engine: 583 | default: 'Dillo' 584 | 585 | #Dolphin 586 | - regex: 'Dolfin(?:/(\d+[\.\d]+))?|dolphin' 587 | name: 'Dolphin' 588 | version: '$1' 589 | engine: 590 | default: 'WebKit' 591 | 592 | #Elinks 593 | - regex: 'Elinks(?:/(\d+[\.\d]+))?' 594 | name: 'Elinks' 595 | version: '$1' 596 | engine: 597 | default: 'Text-based' 598 | 599 | #Element Browser 600 | - regex: 'Element Browser(?:[ /](\d+[\.\d]+))?' 601 | name: 'Element Browser' 602 | version: '$1' 603 | 604 | #Firebird 605 | - regex: 'Firebird(?! Build)(?:/(\d+[\.\d]+))?' 606 | name: 'Firebird' 607 | version: '$1' 608 | engine: 609 | default: 'Gecko' 610 | 611 | #Fluid 612 | - regex: 'Fluid(?:/(\d+[\.\d]+))?' 613 | name: 'Fluid' 614 | version: '$1' 615 | engine: 616 | default: 'WebKit' 617 | 618 | #Galeon 619 | - regex: 'Galeon(?:/(\d+[\.\d]+))?' 620 | name: 'Galeon' 621 | version: '$1' 622 | engine: 623 | default: 'Gecko' 624 | 625 | #Google Earth 626 | - regex: 'Google Earth(?:/(\d+[\.\d]+))?' 627 | name: 'Google Earth' 628 | version: '$1' 629 | engine: 630 | default: 'WebKit' 631 | 632 | #HotJava 633 | - regex: 'HotJava(?:/(\d+[\.\d]+))?' 634 | name: 'HotJava' 635 | version: '$1' 636 | 637 | #IBrowse 638 | - regex: 'IBrowse(?:[ /](\d+[\.\d]+))?' 639 | name: 'IBrowse' 640 | version: '$1' 641 | 642 | #iCab 643 | - regex: 'iCab(?:[ /](\d+[\.\d]+))?' 644 | name: 'iCab' 645 | version: '$1' 646 | engine: 647 | default: 'iCab' 648 | versions: 649 | 4: 'WebKit' 650 | 651 | #Sleipnir 652 | - regex: 'Sleipnir(?:[ /](\d+[\.\d]+))?' 653 | name: 'Sleipnir' 654 | version: '$1' 655 | engine: 656 | default: '' # multi engine 657 | 658 | #Lunascape 659 | - regex: 'Lunascape(?:[/ ](\d+[\.\d]+))?' 660 | name: 'Lunascape' 661 | version: '$1' 662 | engine: 663 | default: '' # multi engine 664 | 665 | #Internet Explorer 666 | - regex: 'IEMobile[ /](\d+[\.\d]+)' 667 | name: 'IE Mobile' 668 | version: '$1' 669 | engine: 670 | default: 'Trident' 671 | - regex: 'MSIE (\d+[\.\d]+).*XBLWP7' 672 | name: 'IE Mobile' 673 | version: '$1' 674 | engine: 675 | default: 'Trident' 676 | - regex: 'MSIE.*Trident/4.0' 677 | name: 'Internet Explorer' 678 | version: 8.0 679 | engine: 680 | default: 'Trident' 681 | - regex: 'MSIE.*Trident/5.0' 682 | name: 'Internet Explorer' 683 | version: 9.0 684 | engine: 685 | default: 'Trident' 686 | - regex: 'MSIE.*Trident/6.0' 687 | name: 'Internet Explorer' 688 | version: 10.0 689 | engine: 690 | default: 'Trident' 691 | - regex: 'Trident/7.0' 692 | name: 'Internet Explorer' 693 | version: 11.0 694 | engine: 695 | default: 'Trident' 696 | - regex: 'MSIE (\d+[\.\d]+)' 697 | name: 'Internet Explorer' 698 | version: '$1' 699 | engine: 700 | default: 'Trident' 701 | - regex: 'IE[ /](\d+[\.\d]++)' 702 | name: 'Internet Explorer' 703 | version: '$1' 704 | engine: 705 | default: 'Trident' 706 | 707 | #Kazehakase 708 | - regex: 'Kazehakase(?:/(\d+[\.\d]+))?' 709 | name: 'Kazehakase' 710 | version: '$1' 711 | engine: 712 | default: '' # multi engine 713 | 714 | #Kindle Browser 715 | - regex: 'Kindle/(\d+[\.\d]+)' 716 | name: 'Kindle Browser' 717 | version: '$1' 718 | 719 | #K-meleon 720 | - regex: 'K-meleon(?:/(\d+[\.\d]+))?' 721 | name: 'K-meleon' 722 | version: '$1' 723 | engine: 724 | default: 'Gecko' 725 | 726 | #Links 727 | - regex: 'Links(?: \((\d+[\.\d]+))?' 728 | name: 'Links' 729 | version: '$1' 730 | engine: 731 | default: 'Text-based' 732 | 733 | # LG Browser 734 | - regex: 'LG Browser(?:/(\d+[\.\d]+))' 735 | name: 'LG Browser' 736 | version: '$1' 737 | 738 | # LuaKit 739 | - regex: 'LuaKit(?:/(\d+[\.\d]+))?' 740 | name: 'LuaKit' 741 | version: '$1' 742 | 743 | #Openwave Mobile Browser 744 | - regex: 'UP.Browser(?:/(\d+[\.\d]+))?' 745 | name: 'Openwave Mobile Browser' 746 | version: '$1' 747 | - regex: 'Openwave(?:/(\d+[\.\d]+))?' 748 | name: 'Openwave Mobile Browser' 749 | version: '$1' 750 | 751 | #OmniWeb 752 | - regex: 'OmniWeb(?:/[v]?(\d+[\.\d]+))?' 753 | name: 'OmniWeb' 754 | version: '$1' 755 | engine: 756 | default: 'WebKit' 757 | 758 | #Phoenix 759 | - regex: 'Phoenix(?:/(\d+[\.\d]+))?' 760 | name: 'Phoenix' 761 | version: '$1' 762 | 763 | #Mobile Silk 764 | - regex: 'Silk(?:/(\d+[\.\d]+))?' 765 | name: 'Mobile Silk' 766 | version: '$1' 767 | engine: 768 | default: 'Blink' 769 | 770 | #NetFront 771 | - regex: 'NetFrontLifeBrowser(?:/(\d+[\.\d]+))?' 772 | name: 'NetFront Life' 773 | version: '$1' 774 | engine: 775 | default: 'NetFront' 776 | - regex: 'NetFront(?:/(\d+[\.\d]+))?' 777 | name: 'NetFront' 778 | version: '$1' 779 | engine: 780 | default: 'NetFront' 781 | - regex: 'PLAYSTATION|NINTENDO 3|AppleWebKit.+ NX/\d+\.\d+\.\d+' 782 | name: 'NetFront' 783 | version: '' 784 | 785 | #NetPositive 786 | - regex: 'NetPositive(?:/(\d+[\.\d]+))?' 787 | name: 'NetPositive' 788 | version: '$1' 789 | 790 | #Obigo 791 | - regex: 'Obigo[ ]?(?:InternetBrowser|Browser)?(?:[ /]([a-z0-9]*))?' 792 | name: 'Obigo' 793 | version: '$1' 794 | - regex: 'Obigo|Teleca' 795 | name: 'Obigo' 796 | version: '' 797 | 798 | #Odyssey Web Browser 799 | - regex: 'Odyssey Web Browser(?:.*OWB/(\d+[\.\d]+))?' 800 | name: 'Odyssey Web Browser' 801 | version: '$1' 802 | 803 | #Off By One 804 | - regex: 'OffByOne' 805 | name: 'Off By One' 806 | version: '' 807 | 808 | #ONE Browser 809 | - regex: 'OneBrowser(?:[ /](\d+[\.\d]+))?' 810 | name: 'ONE Browser' 811 | version: '$1' 812 | engine: 813 | default: 'WebKit' 814 | 815 | #Oregano 816 | - regex: 'Oregano(?:[ /](\d+[\.\d]+))?' 817 | name: 'Oregano' 818 | version: '$1' 819 | 820 | #Otter Browser 821 | - regex: 'Otter(?:[ /](\d+[\.\d]+))?' 822 | name: 'Otter Browser' 823 | version: '$1' 824 | 825 | #Polaris 826 | - regex: '(?:Polaris|Embider)(?:[/ ](\d+[\.\d]+))?' 827 | name: 'Polaris' 828 | version: '$1' 829 | 830 | #SEMC Browser 831 | - regex: 'SEMC-Browser(?:[/ ](\d+[\.\d]+))?' 832 | name: 'SEMC-Browser' 833 | version: '$1' 834 | 835 | #Seraphic Sraf 836 | - regex: 'Sraf(?:[/ ](\d+[\.\d]+))?' 837 | name: 'Seraphic Sraf' 838 | version: '$1' 839 | engine: 840 | default: 'Blink' 841 | 842 | #Shiira 843 | - regex: 'Shiira(?:[/ ](\d+[\.\d]+))?' 844 | name: 'Shiira' 845 | version: '$1' 846 | engine: 847 | default: 'WebKit' 848 | 849 | #Skyfire 850 | - regex: 'Skyfire(?:[/ ](\d+[\.\d]+))?' 851 | name: 'Skyfire' 852 | version: '$1' 853 | 854 | #Snowshoe 855 | - regex: 'Snowshoe(?:/(\d+[\.\d]+))?' 856 | name: 'Snowshoe' 857 | version: '$1' 858 | engine: 859 | default: 'WebKit' 860 | 861 | #Sunrise 862 | - regex: 'Sunrise(?:Browser)?(?:/(\d+[\.\d]+))?' 863 | name: 'Sunrise' 864 | version: '$1' 865 | 866 | #SuperBird 867 | - regex: 'SuperBird(?:/(\d+[\.\d]+))?' 868 | name: 'SuperBird' 869 | version: '$1' 870 | 871 | #Vision Mobile Browser 872 | - regex: 'Vision-Browser(?:/(\d+[\.\d]+))' 873 | name: 'Vision Mobile Browser' 874 | version: '$1' 875 | 876 | #WeTab Browser 877 | - regex: 'WeTab-Browser' 878 | name: 'WeTab Browser' 879 | version: '' 880 | 881 | #Xiino 882 | - regex: 'Xiino(?:/(\d+[\.\d]+))?' 883 | name: 'Xiino' 884 | version: '$1' 885 | 886 | #Nokia Browser 887 | - regex: '(?:NokiaBrowser|BrowserNG)(?:/(\d+[\.\d]+))?' 888 | name: 'Nokia Browser' 889 | version: '$1' 890 | - regex: 'Series60/5\.0' 891 | name: 'Nokia Browser' 892 | version: '7.0' 893 | - regex: 'Series60/(\d+[\.\d]+)' 894 | name: 'Nokia OSS Browser' 895 | version: '$1' 896 | - regex: 'S40OviBrowser/(\d+[\.\d]+)' 897 | name: 'Nokia Ovi Browser' 898 | version: '$1' 899 | - regex: '^Nokia|Nokia[EN]?\d+' 900 | name: 'Nokia Browser' 901 | version: '' 902 | 903 | #BlackBerry Browser 904 | - regex: 'BlackBerry|PlayBook|BB10' 905 | name: 'BlackBerry Browser' 906 | version: '' 907 | 908 | #Android Browser 909 | - regex: 'Android' 910 | name: 'Android Browser' 911 | version: '' 912 | engine: 913 | default: 'WebKit' 914 | 915 | #Safari 916 | - regex: '(?:(?:iPod|iPad|iPhone).+Version|MobileSafari)/(\d+[\.\d]+)' 917 | name: 'Mobile Safari' 918 | version: '$1' 919 | engine: 920 | default: 'WebKit' 921 | - regex: 'Version/(\d+[\.\d]+).*Mobile.*Safari/' 922 | name: 'Mobile Safari' 923 | version: '$1' 924 | engine: 925 | default: 'WebKit' 926 | - regex: '(?:iPod|iPhone|iPad)' 927 | name: 'Mobile Safari' 928 | version: '' 929 | engine: 930 | default: 'WebKit' 931 | - regex: 'Version/(\d+[\.\d]+).*Safari/|Safari/\d+' 932 | name: 'Safari' 933 | version: '$1' 934 | engine: 935 | default: 'WebKit' 936 | --------------------------------------------------------------------------------