From ef6ec5940264fbd0449fb5af07462d67c349d0d1 Mon Sep 17 00:00:00 2001 From: Daniel Wykerd <45672955+Wykerd@users.noreply.github.com> Date: Sat, 23 Jul 2022 20:05:53 +0200 Subject: [PATCH] feat: smaller user-agent list (#112) (#113) --- package-lock.json | 104 ------------------------------------- package.json | 3 +- scripts/get-agents.mjs | 52 +++++++++++++++++++ src/core/Player.ts | 2 +- src/core/Session.ts | 2 +- src/utils/HTTPClient.ts | 2 +- src/utils/Utils.ts | 17 ++---- src/utils/user-agents.json | 58 +++++++++++++++++++++ 8 files changed, 119 insertions(+), 121 deletions(-) create mode 100644 scripts/get-agents.mjs create mode 100644 src/utils/user-agents.json diff --git a/package-lock.json b/package-lock.json index 41b9f851..eff6c613 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "flat": "^5.0.2", "protocol-buffers-encodings": "^1.1.1", "undici": "^5.7.0", - "user-agents": "^1.0.1078", "xml-js": "^1.6.11", "xmlbuilder2": "^3.0.2" }, @@ -2023,14 +2022,6 @@ "node": ">=0.10.0" } }, - "node_modules/detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", - "engines": { - "node": ">=8" - } - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -2061,14 +2052,6 @@ "node": ">=8" } }, - "node_modules/docopt": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", - "integrity": "sha512-NqTbaYeE4gA/wU1hdKFdU+AFahpDOpgGLzHP42k6H6DKExJd0A55KEVWYhL9FEmHmgeLvEU2vuKXDuU+4yToOw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2081,19 +2064,6 @@ "node": ">=6.0.0" } }, - "node_modules/dot-json": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/dot-json/-/dot-json-1.2.2.tgz", - "integrity": "sha512-AKL+GsO4wSEU4LU+fAk/PqN4nQ6PB1vT3HpMiZous9xCzK5S0kh4DzfUY0EfU67jsIXLlu0ty71659N9Nmg+Tw==", - "dependencies": { - "detect-indent": "~6.0.0", - "docopt": "~0.6.2", - "underscore-keypath": "~0.0.22" - }, - "bin": { - "dot-json": "bin/dot-json.js" - } - }, "node_modules/electron-to-chromium": { "version": "1.4.192", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.192.tgz", @@ -4015,11 +3985,6 @@ "node": ">=8" } }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4983,19 +4948,6 @@ "node": ">=4.2.0" } }, - "node_modules/underscore": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", - "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==" - }, - "node_modules/underscore-keypath": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/underscore-keypath/-/underscore-keypath-0.0.22.tgz", - "integrity": "sha512-fU7aYj1J2LQd+jqdQ67AlCOZKK3Pl+VErS8fGYcgZG75XB9/bY+RLM+F2xEcKHhHNtLvqqFyXAoZQlLYfec3Xg==", - "dependencies": { - "underscore": "*" - } - }, "node_modules/undici": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.0.tgz", @@ -5039,15 +4991,6 @@ "punycode": "^2.1.0" } }, - "node_modules/user-agents": { - "version": "1.0.1079", - "resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.0.1079.tgz", - "integrity": "sha512-aJxAmvMUiSttvDVwTXg0mOjN4roVfGlYhufRrdrHNqDGPY5avwSk78YNoBcN3Au7/fkGwVlt1Z4/ddNLWGqJ7A==", - "dependencies": { - "dot-json": "^1.2.2", - "lodash.clonedeep": "^4.5.0" - } - }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -6742,11 +6685,6 @@ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, - "detect-indent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", - "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==" - }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -6768,11 +6706,6 @@ "path-type": "^4.0.0" } }, - "docopt": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", - "integrity": "sha512-NqTbaYeE4gA/wU1hdKFdU+AFahpDOpgGLzHP42k6H6DKExJd0A55KEVWYhL9FEmHmgeLvEU2vuKXDuU+4yToOw==" - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -6782,16 +6715,6 @@ "esutils": "^2.0.2" } }, - "dot-json": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/dot-json/-/dot-json-1.2.2.tgz", - "integrity": "sha512-AKL+GsO4wSEU4LU+fAk/PqN4nQ6PB1vT3HpMiZous9xCzK5S0kh4DzfUY0EfU67jsIXLlu0ty71659N9Nmg+Tw==", - "requires": { - "detect-indent": "~6.0.0", - "docopt": "~0.6.2", - "underscore-keypath": "~0.0.22" - } - }, "electron-to-chromium": { "version": "1.4.192", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.192.tgz", @@ -8141,11 +8064,6 @@ "p-locate": "^4.1.0" } }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -8841,19 +8759,6 @@ "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true }, - "underscore": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", - "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==" - }, - "underscore-keypath": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/underscore-keypath/-/underscore-keypath-0.0.22.tgz", - "integrity": "sha512-fU7aYj1J2LQd+jqdQ67AlCOZKK3Pl+VErS8fGYcgZG75XB9/bY+RLM+F2xEcKHhHNtLvqqFyXAoZQlLYfec3Xg==", - "requires": { - "underscore": "*" - } - }, "undici": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.0.tgz", @@ -8878,15 +8783,6 @@ "punycode": "^2.1.0" } }, - "user-agents": { - "version": "1.0.1079", - "resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.0.1079.tgz", - "integrity": "sha512-aJxAmvMUiSttvDVwTXg0mOjN4roVfGlYhufRrdrHNqDGPY5avwSk78YNoBcN3Au7/fkGwVlt1Z4/ddNLWGqJ7A==", - "requires": { - "dot-json": "^1.2.2", - "lodash.clonedeep": "^4.5.0" - } - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", diff --git a/package.json b/package.json index 3574c4e0..55aae9f0 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "flat": "^5.0.2", "protocol-buffers-encodings": "^1.1.1", "undici": "^5.7.0", - "user-agents": "^1.0.1078", "xml-js": "^1.6.11", "xmlbuilder2": "^3.0.2" }, @@ -83,4 +82,4 @@ "like", "api" ] -} \ No newline at end of file +} diff --git a/scripts/get-agents.mjs b/scripts/get-agents.mjs new file mode 100644 index 00000000..50caf367 --- /dev/null +++ b/scripts/get-agents.mjs @@ -0,0 +1,52 @@ +import { fetch } from "undici"; +import { gunzip } from "zlib"; +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; +import { writeFile } from "fs/promises"; + +(async () => { + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const buf = await (await fetch('https://github.com/intoli/user-agents/blob/master/src/user-agents.json.gz?raw=true')).arrayBuffer(); +const bytes = new Uint8Array(buf); + +// Only get desktop and mobile agents +const allowed_agents = new Set([ + 'desktop', + 'mobile', +]) + +const decompressed = await new Promise((resolve, reject) => { + gunzip(bytes, (err, result) => { + if (err) { + reject(err); + } else { + resolve(result.buffer); + } + }); +}); + +const contents = new TextDecoder().decode(decompressed); + +const agents = JSON.parse(contents); + +if (!Array.isArray(agents)) { + throw new Error('Invalid user-agents.json'); +} + +const agentsByDevice = agents.reduce((acc, agent) => { + const device = agent.deviceCategory; + if (!allowed_agents.has(device)) + return acc; + if (!acc[device]) { + acc[device] = []; + } + // we dont want to massive of a list of agents for each device + if (acc[device].length <= 25) acc[device].push(agent.userAgent); + return acc; +}, {}); + +await writeFile(resolve(__dirname, '..', 'src', 'utils', 'user-agents.json'), JSON.stringify(agentsByDevice, null, 2)); + +})(); diff --git a/src/core/Player.ts b/src/core/Player.ts index 6aa79009..af55f5d6 100644 --- a/src/core/Player.ts +++ b/src/core/Player.ts @@ -124,7 +124,7 @@ export default class Player { const player_res = await fetch(player_url, { headers: { - 'user-agent': getRandomUserAgent('desktop').userAgent + 'user-agent': getRandomUserAgent('desktop') } }); diff --git a/src/core/Session.ts b/src/core/Session.ts index d0939933..ae005db3 100644 --- a/src/core/Session.ts +++ b/src/core/Session.ts @@ -153,7 +153,7 @@ export default class Session extends EventEmitterLike { const res = await fetch(url, { headers: { 'accept-language': lang, - 'user-agent': getRandomUserAgent('desktop').userAgent, + 'user-agent': getRandomUserAgent('desktop'), 'accept': '*/*', 'referer': 'https://www.youtube.com/sw.js', 'cookie': `PREF=tz=${tz.replace('/', '.')}` diff --git a/src/utils/HTTPClient.ts b/src/utils/HTTPClient.ts index 20e37381..e4e81ffc 100644 --- a/src/utils/HTTPClient.ts +++ b/src/utils/HTTPClient.ts @@ -54,7 +54,7 @@ export default class HTTPClient { request_headers.set('x-youtube-client-version', this.#session.context.client.clientVersion || ''); if (isServer()) { - request_headers.set('User-Agent', getRandomUserAgent('desktop').userAgent); + request_headers.set('User-Agent', getRandomUserAgent('desktop')); request_headers.set('origin', request_url.origin); } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 879961ca..0695b215 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -1,7 +1,7 @@ -import UserAgent from 'user-agents'; import Flatten from 'flat'; import package_json from '../../package.json'; import { FetchFunction } from './HTTPClient'; +import userAgents from './user-agents.json'; const VALID_CLIENTS = new Set([ 'YOUTUBE', 'YTMUSIC' ]); @@ -86,17 +86,10 @@ export type DeviceCategory = 'mobile' | 'desktop'; * Returns a random user agent. * @param type - mobile | desktop */ -export function getRandomUserAgent(type: DeviceCategory): UserAgent['data'] { - switch (type) { - case 'mobile': - return new UserAgent(/Android/).data; - case 'desktop': - return new UserAgent({ - deviceCategory: 'desktop' - }).data; - default: - throw new TypeError('Invalid user agent type specified'); - } +export function getRandomUserAgent(type: DeviceCategory): string { + const available_agents = userAgents[type]; + const random_index = Math.floor(Math.random() * available_agents.length); + return available_agents[random_index]; } export async function sha1Hash(str: string) { diff --git a/src/utils/user-agents.json b/src/utils/user-agents.json new file mode 100644 index 00000000..3b287d9d --- /dev/null +++ b/src/utils/user-agents.json @@ -0,0 +1,58 @@ +{ + "desktop": [ + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.49", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" + ], + "mobile": [ + "Mozilla/5.0 (Linux; Android 12; SAMSUNG SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/17.0 Chrome/96.0.4664.104 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; SM-G781B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; arm_64; Android 12; RMX3081) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.148 YaBrowser/22.7.3.82.00 SA/3 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 11; GM1900) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0675.117 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; 21061119BI) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; HarmonyOS; TEL-AN10; HMSCore 6.6.0.312) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.105 HuaweiBrowser/12.1.1.321 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-cn; Mi Note 2 Build/OPR1.170623.032) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.128 Mobile Safari/537.36 XiaoMi/MiuiBrowser/10.1.1", + "Mozilla/5.0 (Linux; Android 12; IN2013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/103.0.5060.63 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/103.0.5060.63 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 9; moto e6s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 11; ONEPLUS A6013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Linux; Android 12; SM-G986B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.25 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A Prime) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Mobile/15E148 Safari/604.1" + ] +} \ No newline at end of file