diff --git a/user_agents/devices.json b/user_agents/devices.json index c8b7efe..e83d2b2 100644 --- a/user_agents/devices.json +++ b/user_agents/devices.json @@ -8,6 +8,24 @@ "ua_string": "Mozilla/5.0 (Android; Mobile; rv:27.0) Gecko/27.0 Firefox/27.0", "str": "Other / Android / Firefox Mobile 27" }, + "android_tablet_chrome_mobile": { + "is_bot": false, + "is_mobile": false, + "is_pc": false, + "is_tablet": true, + "is_touch_capable": true, + "ua_string": "Mozilla/5.0 (Linux; Android 9; SM-T820 Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/85.0.4183.101 Safari/537.36 ANDROID_APP", + "str": "Samsung SM-T820 / Android 9 / Chrome Mobile WebView 85.0.4183" + }, + "kindle": { + "is_bot": false, + "is_mobile": false, + "is_pc": false, + "is_tablet": true, + "is_touch_capable": true, + "ua_string": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Silk/85.3.5 like Chrome/85.0.4183.126 Safari/537.36", + "str": "Kindle / Linux / Amazon Silk 85.3.5" + }, "blackberry_bold": { "is_bot": false, "is_mobile": true, @@ -53,6 +71,24 @@ "ua_string": "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", "str": "SCH-I800 / Android 2.2 / Android 2.2" }, + "generic_android_tablet": { + "is_bot": false, + "is_mobile": false, + "is_pc": false, + "is_tablet": true, + "is_touch_capable": true, + "ua_string": "Mozilla/5.0 (Linux; Android 10.0; X116L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36", + "str": "X116L / Android 10.0 / Chrome 86.0.4240" + }, + "generic_smart_phone_puffin": { + "is_bot": false, + "is_mobile": true, + "is_pc": false, + "is_tablet": false, + "is_touch_capable": true, + "ua_string": "Mozilla/5.0 (X11; U; U; Linux x86_64; nl-nl) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 Puffin/8.4.0.42081AP", + "str": "Generic Smartphone / Linux / Puffin 8.4.0" + }, "google_bot": { "is_bot": true, "is_mobile": false, @@ -89,6 +125,15 @@ "ua_string": "Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10", "str": "iPad / iOS 3.2 / Mobile Safari 4.0.4" }, + "ipad_puffin": { + "is_bot": false, + "is_mobile": false, + "is_pc": false, + "is_tablet": true, + "is_touch_capable": true, + "ua_string": "Mozilla/5.0 (X11; U; Linux x86_64; nl-NL) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.114 Safari/537.36 Puffin/5.2.3IT", + "str": "iPad / Linux / Puffin 5.2.3" + }, "iphone": { "is_bot": false, "is_mobile": true, @@ -241,6 +286,15 @@ "ua_string": "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1", "str": "PC / Ubuntu / Firefox 15.0.1" }, + "windows_chrome_mobile": { + "is_bot": false, + "is_mobile": false, + "is_pc": true, + "is_tablet": false, + "is_touch_capable": false, + "ua_string": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.64 Safari/537.36Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0", + "str": "PC / Windows 10 / Chrome Mobile WebView 70.0.3538" + }, "windows_ie": { "is_bot": false, "is_mobile": false, @@ -317,7 +371,7 @@ "is_bot": false, "is_mobile": true, "is_pc": false, - "is_tablet": true, + "is_tablet": false, "is_touch_capable": true, "ua_string": "Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1202011015; U; en) Presto/2.9.201 Version/11.50", "str": "Opera / Android 2.3.3 / Opera Mobile 11.50" diff --git a/user_agents/parsers.py b/user_agents/parsers.py index 8fcae30..aba66f0 100644 --- a/user_agents/parsers.py +++ b/user_agents/parsers.py @@ -50,6 +50,10 @@ 'Dell Streak', ) +TABLET_DEVICE_BRANDS = ( + 'Generic_Android_Tablet', +) + TOUCH_CAPABLE_OS_FAMILIES = ( 'iOS', 'Android', @@ -63,7 +67,10 @@ TOUCH_CAPABLE_DEVICE_FAMILIES = ( 'BlackBerry Playbook', 'Blackberry Playbook', + 'Generic Smartphone', + 'iPad', 'Kindle Fire', + 'Kindle' ) EMAIL_PROGRAM_FAMILIES = set(( @@ -179,6 +186,10 @@ def get_browser(self): def is_tablet(self): if self.device.family in TABLET_DEVICE_FAMILIES: return True + if self.device.brand in TABLET_DEVICE_BRANDS: + return True + if self.device.family in MOBILE_DEVICE_FAMILIES: + return False if (self.os.family == 'Android' and self._is_android_tablet()): return True if self.os.family == 'Windows' and self.os.version_string.startswith('RT'): @@ -192,14 +203,13 @@ def is_mobile(self): # First check for mobile device and mobile browser families if self.device.family in MOBILE_DEVICE_FAMILIES: return True + if self.is_tablet or self.is_pc: + return False if self.browser.family in MOBILE_BROWSER_FAMILIES: return True # Device is considered Mobile OS is Android and not tablet # This is not fool proof but would have to suffice for now - if ((self.os.family == 'Android' or self.os.family == 'Firefox OS') - and not self.is_tablet): - return True - if self.os.family == 'BlackBerry OS' and self.device.family != 'Blackberry Playbook': + if self.os.family in ['Android', 'Firefox OS', 'BlackBerry OS']: return True if self.os.family in MOBILE_OS_FAMILIES: return True @@ -237,6 +247,10 @@ def is_touch_capable(self): @property def is_pc(self): + if self.device.family in MOBILE_DEVICE_FAMILIES or \ + self.device.family in TABLET_DEVICE_FAMILIES or \ + self.device.brand in TABLET_DEVICE_BRANDS: + return False # Returns True for "PC" devices (Windows, Mac and Linux) if 'Windows NT' in self.ua_string or self.os.family in PC_OS_FAMILIES or \ self.os.family == 'Windows' and self.os.version_string == 'ME': diff --git a/user_agents/tests.py b/user_agents/tests.py index 345cf82..d2633c0 100644 --- a/user_agents/tests.py +++ b/user_agents/tests.py @@ -9,6 +9,7 @@ iphone_ua_string = 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B179 Safari/7534.48.3' ipad_ua_string = 'Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10' +ipad_mobile_chrome_ua_string = 'Mozilla/5.0 (iPad; CPU OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/86.0.4240.93 Mobile/15E148 Safari/604.1' galaxy_tab_ua_string = 'Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' galaxy_s3_ua_string = 'Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' kindle_fire_ua_string = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-80) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true' @@ -34,6 +35,7 @@ iphone_ua = parse(iphone_ua_string) ipad_ua = parse(ipad_ua_string) +ipad_mobile_chrome_ua = parse(ipad_mobile_chrome_ua_string) galaxy_tab = parse(galaxy_tab_ua_string) galaxy_s3_ua = parse(galaxy_s3_ua_string) kindle_fire_ua = parse(kindle_fire_ua_string) @@ -100,6 +102,7 @@ def test_is_tablet_property(self): self.assertFalse(nokia_n97_ua.is_tablet) self.assertTrue(windows_rt_ua.is_tablet) self.assertTrue(ipad_ua.is_tablet) + self.assertTrue(ipad_mobile_chrome_ua.is_tablet) self.assertTrue(playbook_ua.is_tablet) self.assertTrue(kindle_fire_ua.is_tablet) self.assertTrue(nexus_7_ua.is_tablet) @@ -115,6 +118,7 @@ def test_is_mobile_property(self): self.assertTrue(nokia_n97_ua.is_mobile) self.assertFalse(windows_rt_ua.is_mobile) self.assertFalse(ipad_ua.is_mobile) + self.assertFalse(ipad_mobile_chrome_ua.is_mobile) self.assertFalse(playbook_ua.is_mobile) self.assertFalse(kindle_fire_ua.is_mobile) self.assertFalse(nexus_7_ua.is_mobile) @@ -130,6 +134,7 @@ def test_is_touch_property(self): self.assertTrue(iphone_ua.is_touch_capable) self.assertTrue(galaxy_s3_ua.is_touch_capable) self.assertTrue(ipad_ua.is_touch_capable) + self.assertTrue(ipad_mobile_chrome_ua.is_touch_capable) self.assertTrue(playbook_ua.is_touch_capable) self.assertTrue(kindle_fire_ua.is_touch_capable) self.assertTrue(nexus_7_ua.is_touch_capable) @@ -151,6 +156,7 @@ def test_is_pc(self): self.assertFalse(iphone_ua.is_pc) self.assertFalse(galaxy_s3_ua.is_pc) self.assertFalse(ipad_ua.is_pc) + self.assertFalse(ipad_mobile_chrome_ua.is_pc) self.assertFalse(playbook_ua.is_pc) self.assertFalse(kindle_fire_ua.is_pc) self.assertFalse(nexus_7_ua.is_pc) @@ -174,6 +180,7 @@ def test_is_bot(self): self.assertFalse(iphone_ua.is_bot) self.assertFalse(galaxy_s3_ua.is_bot) self.assertFalse(ipad_ua.is_bot) + self.assertFalse(ipad_mobile_chrome_ua.is_bot) self.assertFalse(playbook_ua.is_bot) self.assertFalse(kindle_fire_ua.is_bot) self.assertFalse(nexus_7_ua.is_bot) @@ -213,6 +220,7 @@ def test_is_email_client(self): def test_strings(self): self.assertEqual(str(iphone_ua), "iPhone / iOS 5.1 / Mobile Safari 5.1") self.assertEqual(str(ipad_ua), "iPad / iOS 3.2 / Mobile Safari 4.0.4") + self.assertEqual(str(ipad_mobile_chrome_ua), "iPad / iOS 13.3 / Chrome Mobile iOS 86.0.4240") self.assertEqual(str(galaxy_tab), "Samsung SCH-I800 / Android 2.2 / Android 2.2") self.assertEqual(str(galaxy_s3_ua), "Samsung GT-I9300 / Android 4.0.4 / Android 4.0.4") self.assertEqual(str(kindle_fire_ua), "Kindle / Android / Amazon Silk 1.1.0-80")