Skip to content

Commit

Permalink
Merge pull request #124 from podigee/matomo-upstream-definition-updat…
Browse files Browse the repository at this point in the history
…es-2024-06-04

Update definitions with Matomo upstream (additions to #122)
  • Loading branch information
spiderpug authored Jul 3, 2024
2 parents 5492c72 + 218bc49 commit 374b4d5
Show file tree
Hide file tree
Showing 111 changed files with 110,173 additions and 57,441 deletions.
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.5
3.3.2
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Change Log

- Updated detection rules from upstream on 2024-06-25

## [1.1.2]
- Updated detection rules from upstream on 2023-11-27

Expand Down
24 changes: 19 additions & 5 deletions README.md

Large diffs are not rendered by default.

77 changes: 55 additions & 22 deletions lib/device_detector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ class DeviceDetector
def initialize(user_agent, headers = nil)
@client_hint = ClientHint.new(headers)
utf8_user_agent = encode_user_agent_if_needed(user_agent)
@user_agent = set_user_agent(utf8_user_agent)
@user_agent = build_user_agent(utf8_user_agent)
end

# https://github.com/matomo-org/device-detector/blob/c235832dba13961ab0f71b681616baf1aa48de23/Parser/Device/AbstractDeviceParser.php#L1873
def set_user_agent(user_agent)
# https://github.com/matomo-org/device-detector/blob/a2535ff3b63e4187f1d3440aed24ff43d74fb7f1/Parser/Device/AbstractDeviceParser.php#L2065-L2073
def build_user_agent(user_agent)
return user_agent if client_hint.model.nil?

regex = build_regex('Android 10[.\d]*; K(?: Build/|[;)])')
return user_agent unless user_agent =~ regex

version = client_hint.os_version || '10'

user_agent.gsub(regex, "Android #{version}, #{client_hint.model}")
user_agent.gsub(/(Android 10[.\d]*; K)/, "Android #{version}; #{client_hint.model}")
end

def encode_user_agent_if_needed(user_agent)
Expand Down Expand Up @@ -69,6 +69,8 @@ def os_name

def os_full_version
return if skip_os_version?
return os.full_version if pico_os_fix?
return fire_os_version if fire_os_fix?

client_hint.os_version || os.full_version
end
Expand All @@ -84,36 +86,40 @@ def device_brand

# Assume all devices running iOS / Mac OS are from Apple
brand = device.brand
brand = 'Apple' if brand.nil? && %w[iPadOS tvOS watchOS iOS Mac].include?(os_name)
brand = 'Apple' if brand.nil? && DeviceDetector::OS::APPLE_OS_NAMES.include?(os_name)

brand
end

def device_type
t = device.type

t = nil if fake_ua?

# Chrome on Android passes the device type based on the keyword 'Mobile'
# If it is present the device should be a smartphone, otherwise it's a tablet
# See https://developer.chrome.com/multidevice/user-agent#chrome_for_android_user_agent
# Note: We do not check for browser (family) here, as there might be mobile apps using Chrome,
# that won't have a detected browser, but can still be detected. So we check the useragent for
# Chrome instead.
if t.nil? && os_family == 'Android' && user_agent =~ build_regex('Chrome\/[\.0-9]*')
if user_agent =~ build_regex('(?:Mobile|eliboM) Safari\/')
t = 'smartphone'
elsif user_agent =~ build_regex('(?!Mobile )Safari\/')
t = 'tablet'
end
t = user_agent =~ build_regex('(?:Mobile|eliboM)') ? 'smartphone' : 'tablet'
end

# Some UA contain the fragment 'Pad/APad', so we assume those devices as tablets
t = 'tablet' if t == 'smartphone' && user_agent =~ build_regex('Pad\/APad')

# Some UA contain the fragment 'Android; Tablet;' or 'Opera Tablet', so we assume those devices
# as tablets
t = 'tablet' if t.nil? && android_tablet_fragment? || opera_tablet?
t = 'tablet' if t.nil? && (android_tablet_fragment? || opera_tablet?)

# Some user agents simply contain the fragment 'Android; Mobile;', so we assume those devices
# as smartphones
t = 'smartphone' if t.nil? && android_mobile_fragment?

# Some UA contains the 'Android; Mobile VR;' fragment
t = 'wearable' if t.nil? && android_vr_fragment?

# Android up to 3.0 was designed for smartphones only. But as 3.0,
# which was tablet only, was published too late, there were a
# bunch of tablets running with 2.x With 4.0 the two trees were
Expand Down Expand Up @@ -156,14 +162,18 @@ def device_type
t = 'tv' if opera_tv_store?

# All devices that contain Andr0id in string are assumed to be a tv
t = 'tv' if user_agent =~ build_regex('Andr0id|Android TV')
if user_agent =~ build_regex('Andr0id|(?:Android(?: UHD)?|Google) TV|\(lite\) TV|BRAVIA')
t = 'tv'
end

# All devices running Tizen TV or SmartTV are assumed to be a tv
t = 'tv' if t.nil? && tizen_samsung_tv?

# Devices running Kylo or Espital TV Browsers are assumed to be a TV
# Devices running those clients are assumed to be a TV
t = 'tv' if ['Kylo', 'Espial TV Browser', 'LUJO TV Browser', 'LogicUI TV Browser',
'Open TV Browser'].include?(name)
'Open TV Browser', 'Seraphic Sraf', 'Opera Devices', 'Crow Browser',
'Vewd Browser', 'TiviMate', 'Quick Search TV', 'QJY TV Browser',
'TV Bro'].include?(name)

# All devices containing TV fragment are assumed to be a tv
t = 'tv' if t.nil? && user_agent =~ build_regex('\(TV;')
Expand Down Expand Up @@ -233,9 +243,9 @@ def os
@os ||= OS.new(user_agent)
end

# https://github.com/matomo-org/device-detector/blob/827a3fab7e38c3274c18d2f5f5bc2a78b7ef4a3a/DeviceDetector.php#L921C5-L921C5
# https://github.com/matomo-org/device-detector/blob/67ae11199a5129b42fa8b985d372ea834104fe3a/DeviceDetector.php#L931-L938
def fake_ua?
os_name == 'Android' && device.brand == 'Apple'
device.brand == 'Apple' && !DeviceDetector::OS::APPLE_OS_NAMES.include?(os_name)
end

# https://github.com/matomo-org/device-detector/blob/be1c9ef486c247dc4886668da5ed0b1c49d90ba8/Parser/Client/Browser.php#L772
Expand All @@ -245,28 +255,51 @@ def mobile_fix?
end

def linux_fix?
client_hint.platform == 'Linux' && os.name == 'Android' && client_hint.mobile == '?0'
client_hint.platform == 'Linux' &&
%w[iOS Android].include?(os.name) &&
%w[?0 0].include?(client_hint.mobile)
end

# Related to issue mentionned in device.rb#1562
def fix_for_x_music
user_agent&.include?('X-music Ⅲ') ? 'X-Music III' : nil
end

def pico_os_fix?
client_hint.os_name == 'Pico OS'
end

# https://github.com/matomo-org/device-detector/blob/323629cb679c8572a9745cba9c3803fee13f3cf6/Parser/OperatingSystem.php#L398-L403
def fire_os_fix?
!client_hint.platform.nil? && os.name == 'Fire OS'
end

def fire_os_version
DeviceDetector::OS
.mapped_os_version(client_hint.os_version, DeviceDetector::OS::FIRE_OS_VERSION_MAPPING)
end

# https://github.com/matomo-org/device-detector/blob/323629cb679c8572a9745cba9c3803fee13f3cf6/Parser/OperatingSystem.php#L378-L383
def skip_os_version?
!client_hint.os_family.nil? && client_hint.os_family != os.family
!client_hint.os_family.nil? &&
client_hint.os_version.nil? &&
client_hint.os_family != os.family
end

def android_tablet_fragment?
user_agent =~ build_regex('Android( [\.0-9]+)?; Tablet;')
user_agent =~ build_regex('Android( [\.0-9]+)?; Tablet;|Tablet(?! PC)|.*\-tablet$')
end

def android_mobile_fragment?
user_agent =~ build_regex('Android( [\.0-9]+)?; Mobile;')
user_agent =~ build_regex('Android( [\.0-9]+)?; Mobile;|.*\-mobile$')
end

def android_vr_fragment?
user_agent =~ build_regex('Android( [\.0-9]+)?; Mobile VR;| VR ')
end

def desktop_fragment?
user_agent =~ build_regex('Desktop (x(?:32|64)|WOW64);')
user_agent =~ build_regex('Desktop(?: (x(?:32|64)|WOW64))?;')
end

def touch_enabled?
Expand Down Expand Up @@ -300,7 +333,7 @@ def desktop?
# Check for browsers available for mobile devices only
return false if uses_mobile_browser?

os.desktop?
DeviceDetector::OS::DESKTOP_OSS.include?(os_family)
end

def build_regex(src)
Expand Down
Loading

0 comments on commit 374b4d5

Please sign in to comment.