Skip to main content
Glama
userAgent.ts7.3 kB
import { UserAgentInfo, iPhoneModelMap } from '../types/index.js'; /** * 解析 User-Agent 字符串 * @param userAgent User-Agent 字符串 * @returns 解析后的设备信息 */ export function parseUserAgent(userAgent: string): UserAgentInfo { if (!userAgent || typeof userAgent !== 'string') { return { valid: false, rawUserAgent: userAgent, error: "User-Agent 字符串无效" }; } const result: UserAgentInfo = { valid: true, rawUserAgent: userAgent }; try { // 解析操作系统和版本 // iOS: "iPhone; CPU iPhone OS 18_3_2 like Mac OS X" 或 "iOS 18.3.2" const iosMatch = userAgent.match(/(?:iPhone OS|iOS)\s+([\d_\.]+)/i); if (iosMatch) { result.os = "iOS"; result.osVersion = iosMatch[1].replace(/_/g, '.'); } // Android: "Android 13" 或 "Android/13" const androidMatch = userAgent.match(/Android[\s\/]+([\d\.]+)/i); if (androidMatch) { result.os = "Android"; result.osVersion = androidMatch[1]; } // 解析设备信息: Device/(Apple Inc.;iPhone15,3) const deviceMatch = userAgent.match(/Device\/\(([^;]+);([^\)]+)\)/); if (deviceMatch) { result.deviceBrand = deviceMatch[1]; result.deviceModel = deviceMatch[2]; // 如果是 iPhone,尝试映射到商业名称 if (result.deviceModel && iPhoneModelMap[result.deviceModel]) { result.deviceName = iPhoneModelMap[result.deviceModel]; } else { result.deviceName = result.deviceModel; } } // 如果没有 Device 字段,尝试从 UA 中识别设备类型 if (!result.deviceBrand) { if (userAgent.includes('iPhone')) { result.deviceBrand = 'Apple Inc.'; result.deviceName = 'iPhone'; } else if (userAgent.includes('iPad')) { result.deviceBrand = 'Apple Inc.'; result.deviceName = 'iPad'; } else if (userAgent.includes('Android')) { // 尝试识别 Android 设备品牌 const brands = ['Samsung', 'Huawei', 'Xiaomi', 'OPPO', 'vivo', 'OnePlus', 'Google']; for (const brand of brands) { if (userAgent.includes(brand)) { result.deviceBrand = brand; break; } } } } // 解析应用信息: discover/9.1 const appMatch = userAgent.match(/(\w+)\/([\d\.]+)/); if (appMatch && !['Mozilla', 'AppleWebKit', 'Mobile'].includes(appMatch[1])) { result.appName = appMatch[1]; result.appVersion = appMatch[2]; } // 解析 Build 版本: Build/9010812 const buildMatch = userAgent.match(/Build\/([\d]+)/); if (buildMatch) { result.buildVersion = buildMatch[1]; } // 解析分辨率: Resolution/1290*2796 const resolutionMatch = userAgent.match(/Resolution\/([\d]+\*[\d]+)/); if (resolutionMatch) { result.resolution = resolutionMatch[1]; } // 解析屏幕缩放: Scale/3.00 const scaleMatch = userAgent.match(/Scale\/([\d\.]+)/); if (scaleMatch) { result.scale = scaleMatch[1]; } // 解析网络类型: NetType/WiFi 或 NetType/CellNetwork const netTypeMatch = userAgent.match(/NetType\/(\w+)/); if (netTypeMatch) { result.netType = netTypeMatch[1]; } // 解析 WebView: WKWebView=1 if (userAgent.includes('WKWebView')) { result.webView = 'WKWebView'; } else if (userAgent.includes('WebView')) { result.webView = 'WebView'; } // 解析浏览器类型 if (userAgent.includes('Chrome') && !userAgent.includes('Edge')) { result.browser = 'Chrome'; } else if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) { result.browser = 'Safari'; } else if (userAgent.includes('Firefox')) { result.browser = 'Firefox'; } else if (userAgent.includes('Edge')) { result.browser = 'Edge'; } } catch (error) { result.valid = false; result.error = `解析失败: ${error instanceof Error ? error.message : '未知错误'}`; } return result; } /** * 格式化 User-Agent 解析结果 * @param info 解析后的 UA 信息 * @returns 格式化的字符串 */ export function formatUserAgentInfo(info: UserAgentInfo): string { if (!info.valid) { return `❌ User-Agent 解析失败\n\n错误信息: ${info.error || "未知错误"}`; } const lines: string[] = [ `✅ User-Agent 解析成功`, ``, ]; // 设备信息 if (info.deviceBrand || info.deviceName || info.deviceModel) { lines.push(`📱 设备信息:`); if (info.deviceBrand) { lines.push(` 品牌: ${info.deviceBrand}`); } if (info.deviceName) { lines.push(` 型号: ${info.deviceName}`); } if (info.deviceModel && info.deviceModel !== info.deviceName) { lines.push(` 代号: ${info.deviceModel}`); } lines.push(``); } // 系统信息 if (info.os || info.osVersion) { lines.push(`💻 系统信息:`); if (info.os) { lines.push(` 操作系统: ${info.os}`); } if (info.osVersion) { lines.push(` 系统版本: ${info.osVersion}`); } lines.push(``); } // 应用信息 if (info.appName || info.appVersion || info.buildVersion) { lines.push(`📦 应用信息:`); if (info.appName) { lines.push(` 应用名称: ${info.appName}`); } if (info.appVersion) { lines.push(` 应用版本: ${info.appVersion}`); } if (info.buildVersion) { lines.push(` Build 版本: ${info.buildVersion}`); } lines.push(``); } // 屏幕信息 if (info.resolution || info.scale) { lines.push(`📺 屏幕信息:`); if (info.resolution) { const [width, height] = info.resolution.split('*'); lines.push(` 分辨率: ${width} × ${height}`); } if (info.scale) { lines.push(` 缩放比例: ${info.scale}x`); } lines.push(``); } // 网络和浏览器信息 const otherInfo: string[] = []; if (info.netType) { const netTypeName = info.netType === 'WiFi' ? 'Wi-Fi' : info.netType === 'CellNetwork' ? '蜂窝网络' : info.netType; otherInfo.push(` 网络类型: ${netTypeName}`); } if (info.browser) { otherInfo.push(` 浏览器: ${info.browser}`); } if (info.webView) { otherInfo.push(` WebView: ${info.webView}`); } if (otherInfo.length > 0) { lines.push(`🌐 其他信息:`); lines.push(...otherInfo); } return lines.join('\n'); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/liukexina/lkx-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server