UNPKG

unified-video-framework

Version:

Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more

220 lines (179 loc) 6.66 kB
/** * Device Detection Utility * Detects device information for analytics */ import { DeviceDetectionResult, DeviceInfo, NetworkInfo } from '../types/AnalyticsTypes'; export class DeviceDetection { private static instance: DeviceDetection; static getInstance(): DeviceDetection { if (!DeviceDetection.instance) { DeviceDetection.instance = new DeviceDetection(); } return DeviceDetection.instance; } /** * Detect device information */ detectDevice(): DeviceDetectionResult { const userAgent = this.getUserAgent(); return { deviceType: this.getDeviceType(userAgent), os: this.getOS(userAgent), osVersion: this.getOSVersion(userAgent), browser: this.getBrowser(userAgent), browserVersion: this.getBrowserVersion(userAgent), screen: this.getScreenInfo(), userAgent, isMobile: this.isMobile(userAgent), isTablet: this.isTablet(userAgent), isDesktop: this.isDesktop(userAgent), isSmartTV: this.isSmartTV(userAgent), isTizen: this.isTizen(userAgent), isWebOS: this.isWebOS(userAgent), isRoku: this.isRoku(userAgent) }; } /** * Get device information in analytics format */ getDeviceInfo(): DeviceInfo { const detection = this.detectDevice(); return { deviceType: detection.deviceType, os: detection.os, osVersion: detection.osVersion, browser: detection.browser, browserVersion: detection.browserVersion, screen: detection.screen, userAgent: detection.userAgent, language: this.getLanguage(), timezone: this.getTimezone() }; } /** * Get network information */ getNetworkInfo(): NetworkInfo { const connection = this.getConnection(); return { connectionType: connection?.type, effectiveType: connection?.effectiveType, downlink: connection?.downlink, rtt: connection?.rtt, online: navigator?.onLine ?? true }; } private getUserAgent(): string { return typeof navigator !== 'undefined' ? navigator.userAgent : ''; } private getDeviceType(userAgent: string): DeviceInfo['deviceType'] { if (this.isSmartTV(userAgent)) return 'smart_tv'; if (this.isMobile(userAgent)) return 'mobile'; if (this.isTablet(userAgent)) return 'tablet'; return 'desktop'; } private getOS(userAgent: string): string { if (/Windows NT/i.test(userAgent)) return 'Windows'; if (/Mac OS X/i.test(userAgent)) return 'macOS'; if (/Linux/i.test(userAgent)) return 'Linux'; if (/Android/i.test(userAgent)) return 'Android'; if (/iPhone|iPad|iPod/i.test(userAgent)) return 'iOS'; if (/Tizen/i.test(userAgent)) return 'Tizen'; if (/webOS/i.test(userAgent)) return 'webOS'; if (/Roku/i.test(userAgent)) return 'Roku'; return 'Unknown'; } private getOSVersion(userAgent: string): string | undefined { let match; // Windows match = userAgent.match(/Windows NT ([\d.]+)/); if (match) return match[1]; // macOS match = userAgent.match(/Mac OS X ([\d_]+)/); if (match) return match[1].replace(/_/g, '.'); // iOS match = userAgent.match(/OS ([\d_]+)/); if (match) return match[1].replace(/_/g, '.'); // Android match = userAgent.match(/Android ([\d.]+)/); if (match) return match[1]; // Tizen match = userAgent.match(/Tizen ([\d.]+)/); if (match) return match[1]; return undefined; } private getBrowser(userAgent: string): string | undefined { if (/Chrome/i.test(userAgent) && !/Edge/i.test(userAgent)) return 'Chrome'; if (/Firefox/i.test(userAgent)) return 'Firefox'; if (/Safari/i.test(userAgent) && !/Chrome/i.test(userAgent)) return 'Safari'; if (/Edge/i.test(userAgent)) return 'Edge'; if (/Opera/i.test(userAgent)) return 'Opera'; if (/Samsung/i.test(userAgent)) return 'Samsung Internet'; return undefined; } private getBrowserVersion(userAgent: string): string | undefined { let match; // Chrome match = userAgent.match(/Chrome\/([\d.]+)/); if (match && !/Edge/i.test(userAgent)) return match[1]; // Firefox match = userAgent.match(/Firefox\/([\d.]+)/); if (match) return match[1]; // Safari match = userAgent.match(/Version\/([\d.]+).*Safari/); if (match) return match[1]; // Edge match = userAgent.match(/Edge\/([\d.]+)/); if (match) return match[1]; // Opera match = userAgent.match(/Opera.*Version\/([\d.]+)/); if (match) return match[1]; return undefined; } private getScreenInfo(): { width: number; height: number; orientation?: 'portrait' | 'landscape' } { if (typeof window === 'undefined' || !window.screen) { return { width: 1920, height: 1080 }; } const orientation: 'portrait' | 'landscape' = window.screen.width > window.screen.height ? 'landscape' : 'portrait'; return { width: window.screen.width, height: window.screen.height, orientation }; } private getLanguage(): string { if (typeof navigator === 'undefined') return 'en-US'; return navigator.language || 'en-US'; } private getTimezone(): string { if (typeof Intl === 'undefined') return 'UTC'; return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'; } private getConnection(): any { if (typeof navigator === 'undefined') return null; return (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection; } private isMobile(userAgent: string): boolean { return /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent); } private isTablet(userAgent: string): boolean { return /iPad|Android.*(?!.*Mobile)/i.test(userAgent); } private isDesktop(userAgent: string): boolean { return !this.isMobile(userAgent) && !this.isSmartTV(userAgent); } private isSmartTV(userAgent: string): boolean { return /Smart.*TV|Tizen|webOS|Roku|PlayStation|Xbox/i.test(userAgent); } private isTizen(userAgent: string): boolean { return /Tizen/i.test(userAgent); } private isWebOS(userAgent: string): boolean { return /webOS/i.test(userAgent); } private isRoku(userAgent: string): boolean { return /Roku/i.test(userAgent); } } // Global instance export const deviceDetection = DeviceDetection.getInstance();