|
import requests |
|
from urllib.parse import quote |
|
from functools import lru_cache |
|
import os |
|
import json |
|
from functools import lru_cache |
|
|
|
apple_device_mapping = { |
|
"Watch1,1": "Apple Watch 38mm case", |
|
"Watch1,2": "Apple Watch 42mm case", |
|
"Watch2,3": "Apple Watch Series 2 38mm case", |
|
"Watch2,4": "Apple Watch Series 2 42mm case", |
|
"Watch2,6": "Apple Watch Series 1 38mm case", |
|
"Watch2,7": "Apple Watch Series 1 42mm case", |
|
"Watch3,1": "Apple Watch Series 3 38mm case", |
|
"Watch3,2": "Apple Watch Series 3 42mm case", |
|
"Watch3,3": "Apple Watch Series 3 38mm case", |
|
"Watch3,4": "Apple Watch Series 3 42mm case", |
|
"Watch4,1": "Apple Watch Series 4 40mm case", |
|
"Watch4,2": "Apple Watch Series 4 44mm case", |
|
"Watch4,3": "Apple Watch Series 4 40mm case", |
|
"Watch4,4": "Apple Watch Series 4 44mm case", |
|
"Watch5,1": "Apple Watch Series 5 40mm case", |
|
"Watch5,10": "Apple Watch SE 44mm case", |
|
"Watch5,11": "Apple Watch SE 40mm case", |
|
"Watch5,12": "Apple Watch SE 44mm case", |
|
"Watch5,2": "Apple Watch Series 5 44mm case", |
|
"Watch5,3": "Apple Watch Series 5 40mm case", |
|
"Watch5,4": "Apple Watch Series 5 44mm case", |
|
"Watch5,9": "Apple Watch SE 40mm case", |
|
"Watch6,1": "Apple Watch Series 6 40mm case", |
|
"Watch6,10": "Apple Watch SE 40mm case", |
|
"Watch6,11": "Apple Watch SE 44mm case", |
|
"Watch6,12": "Apple Watch SE 40mm case", |
|
"Watch6,13": "Apple Watch SE 44mm case", |
|
"Watch6,14": "Apple Watch Series 8 41mm case", |
|
"Watch6,15": "Apple Watch Series 8 45mm case", |
|
"Watch6,16": "Apple Watch Series 8 41mm case", |
|
"Watch6,17": "Apple Watch Series 8 45mm case", |
|
"Watch6,18": "Apple Watch Ultra", |
|
"Watch6,2": "Apple Watch Series 6 44mm case", |
|
"Watch6,3": "Apple Watch Series 6 40mm case", |
|
"Watch6,4": "Apple Watch Series 6 44mm case", |
|
"Watch6,6": "Apple Watch Series 7 41mm case", |
|
"Watch6,7": "Apple Watch Series 7 45mm case", |
|
"Watch6,8": "Apple Watch Series 7 41mm case", |
|
"Watch6,9": "Apple Watch Series 7 45mm case", |
|
"Watch7,1": "Apple Watch Series 9 41mm case", |
|
"Watch7,10": "Apple Watch Series 10 42mm case", |
|
"Watch7,11": "Apple Watch Series 10 46mm", |
|
"Watch7,2": "Apple Watch Series 9 45mm case", |
|
"Watch7,3": "Apple Watch Series 9 41mm case", |
|
"Watch7,4": "Apple Watch Series 9 45mm case", |
|
"Watch7,5": "Apple Watch Ultra 2", |
|
"Watch7,8": "Apple Watch Series 10 42mm case", |
|
"Watch7,9": "Apple Watch Series 10 46mm case (GPS", |
|
"arm64": "iPhone Simulator", |
|
"i386": "iPhone Simulator", |
|
"iPad1,1": "iPad", |
|
"iPad1,2": "iPad 3G", |
|
"iPad11,1": "iPad mini 5th Gen", |
|
"iPad11,2": "iPad mini 5th Gen", |
|
"iPad11,3": "iPad Air 3rd Gen", |
|
"iPad11,4": "iPad Air 3rd Gen", |
|
"iPad11,6": "iPad 8th Gen", |
|
"iPad11,7": "iPad 8th Gen", |
|
"iPad12,1": "iPad 9th Gen", |
|
"iPad12,2": "iPad 9th Gen", |
|
"iPad13,1": "iPad Air 4th Gen", |
|
"iPad13,10": "iPad Pro 12.9 inch 5th Gen", |
|
"iPad13,11": "iPad Pro 12.9 inch 5th Gen", |
|
"iPad13,16": "iPad Air 5th Gen", |
|
"iPad13,17": "iPad Air 5th Gen", |
|
"iPad13,18": "iPad 10th Gen", |
|
"iPad13,19": "iPad 10th Gen", |
|
"iPad13,2": "iPad Air 4th Gen", |
|
"iPad13,4": "iPad Pro 11 inch 5th Gen", |
|
"iPad13,5": "iPad Pro 11 inch 5th Gen", |
|
"iPad13,6": "iPad Pro 11 inch 5th Gen", |
|
"iPad13,7": "iPad Pro 11 inch 5th Gen", |
|
"iPad13,8": "iPad Pro 12.9 inch 5th Gen", |
|
"iPad13,9": "iPad Pro 12.9 inch 5th Gen", |
|
"iPad14,1": "iPad mini 6th Gen", |
|
"iPad14,10": "iPad Air 13 inch 6th Gen", |
|
"iPad14,11": "iPad Air 13 inch 6th Gen", |
|
"iPad14,2": "iPad mini 6th Gen", |
|
"iPad14,3": "iPad Pro 11 inch 4th Gen", |
|
"iPad14,4": "iPad Pro 11 inch 4th Gen", |
|
"iPad14,5": "iPad Pro 12.9 inch 6th Gen", |
|
"iPad14,6": "iPad Pro 12.9 inch 6th Gen", |
|
"iPad14,8": "iPad Air 11 inch 6th Gen", |
|
"iPad14,9": "iPad Air 11 inch 6th Gen", |
|
"iPad15,3": "iPad Air 11-inch 7th Gen", |
|
"iPad15,4": "iPad Air 11-inch 7th Gen", |
|
"iPad15,5": "iPad Air 13-inch 7th Gen", |
|
"iPad15,6": "iPad Air 13-inch 7th Gen", |
|
"iPad15,7": "iPad 11th Gen", |
|
"iPad15,8": "iPad 11th Gen", |
|
"iPad16,1": "iPad mini 7th Gen", |
|
"iPad16,2": "iPad mini 7th Gen", |
|
"iPad16,3": "iPad Pro 11 inch 5th Gen", |
|
"iPad16,4": "iPad Pro 11 inch 5th Gen", |
|
"iPad16,5": "iPad Pro 12.9 inch 7th Gen", |
|
"iPad16,6": "iPad Pro 12.9 inch 7th Gen", |
|
"iPad2,1": "2nd Gen iPad", |
|
"iPad2,2": "2nd Gen iPad", |
|
"iPad2,3": "2nd Gen iPad", |
|
"iPad2,4": "2nd Gen iPad New Revision", |
|
"iPad2,5": "iPad mini", |
|
"iPad2,6": "iPad mini", |
|
"iPad2,7": "iPad mini", |
|
"iPad3,1": "3rd Gen iPad", |
|
"iPad3,2": "3rd Gen iPad", |
|
"iPad3,3": "3rd Gen iPad", |
|
"iPad3,4": "4th Gen iPad", |
|
"iPad3,5": "4th Gen iPad", |
|
"iPad3,6": "4th Gen iPad", |
|
"iPad4,1": "iPad Air", |
|
"iPad4,2": "iPad Air", |
|
"iPad4,3": "1st Gen iPad Air", |
|
"iPad4,4": "iPad mini Retina", |
|
"iPad4,5": "iPad mini Retina", |
|
"iPad4,6": "iPad mini Retina", |
|
"iPad4,7": "iPad mini 3", |
|
"iPad4,8": "iPad mini 3", |
|
"iPad4,9": "iPad Mini 3", |
|
"iPad5,1": "iPad mini 4", |
|
"iPad5,2": "4th Gen iPad mini", |
|
"iPad5,3": "iPad Air 2", |
|
"iPad5,4": "iPad Air 2", |
|
"iPad6,11": "iPad (2017)", |
|
"iPad6,12": "iPad (2017)", |
|
"iPad6,3": "iPad Pro (9.7 inch)", |
|
"iPad6,4": "iPad Pro (9.7 inch)", |
|
"iPad6,7": "iPad Pro (12.9 inch)", |
|
"iPad6,8": "iPad Pro (12.9 inch)", |
|
"iPad7,1": "iPad Pro 2nd Gen", |
|
"iPad7,11": "iPad 7th Gen 10.2-inch", |
|
"iPad7,12": "iPad 7th Gen 10.2-inch", |
|
"iPad7,2": "iPad Pro 2nd Gen", |
|
"iPad7,3": "iPad Pro 10.5-inch 2nd Gen", |
|
"iPad7,4": "iPad Pro 10.5-inch 2nd Gen", |
|
"iPad7,5": "iPad 6th Gen", |
|
"iPad7,6": "iPad 6th Gen", |
|
"iPad8,1": "iPad Pro 11 inch 3rd Gen", |
|
"iPad8,10": "iPad Pro 11 inch 4th Gen", |
|
"iPad8,11": "iPad Pro 12.9 inch 4th Gen", |
|
"iPad8,12": "iPad Pro 12.9 inch 4th Gen", |
|
"iPad8,2": "iPad Pro 11 inch 3rd Gen", |
|
"iPad8,3": "iPad Pro 11 inch 3rd Gen", |
|
"iPad8,4": "iPad Pro 11 inch 3rd Gen", |
|
"iPad8,5": "iPad Pro 12.9 inch 3rd Gen", |
|
"iPad8,6": "iPad Pro 12.9 inch 3rd Gen", |
|
"iPad8,7": "iPad Pro 12.9 inch 3rd Gen", |
|
"iPad8,8": "iPad Pro 12.9 inch 3rd Gen", |
|
"iPad8,9": "iPad Pro 11 inch 4th Gen", |
|
"iPhone1,1": "iPhone", |
|
"iPhone1,2": "iPhone 3G", |
|
"iPhone10,1": "iPhone 8", |
|
"iPhone10,2": "iPhone 8 Plus", |
|
"iPhone10,3": "iPhone X", |
|
"iPhone10,4": "iPhone 8", |
|
"iPhone10,5": "iPhone 8 Plus", |
|
"iPhone10,6": "iPhone X", |
|
"iPhone11,2": "iPhone XS", |
|
"iPhone11,4": "iPhone XS Max", |
|
"iPhone11,6": "iPhone XS Max", |
|
"iPhone11,8": "iPhone XR", |
|
"iPhone12,1": "iPhone 11", |
|
"iPhone12,3": "iPhone 11 Pro", |
|
"iPhone12,5": "iPhone 11 Pro Max", |
|
"iPhone12,8": "iPhone SE 2nd Gen", |
|
"iPhone13,1": "iPhone 12 Mini", |
|
"iPhone13,2": "iPhone 12", |
|
"iPhone13,3": "iPhone 12 Pro", |
|
"iPhone13,4": "iPhone 12 Pro Max", |
|
"iPhone14,2": "iPhone 13 Pro", |
|
"iPhone14,3": "iPhone 13 Pro Max", |
|
"iPhone14,4": "iPhone 13 Mini", |
|
"iPhone14,5": "iPhone 13", |
|
"iPhone14,6": "iPhone SE 3rd Gen", |
|
"iPhone14,7": "iPhone 14", |
|
"iPhone14,8": "iPhone 14 Plus", |
|
"iPhone15,2": "iPhone 14 Pro", |
|
"iPhone15,3": "iPhone 14 Pro Max", |
|
"iPhone15,4": "iPhone 15", |
|
"iPhone15,5": "iPhone 15 Plus", |
|
"iPhone16,1": "iPhone 15 Pro", |
|
"iPhone16,2": "iPhone 15 Pro Max", |
|
"iPhone17,1": "iPhone 16 Pro", |
|
"iPhone17,2": "iPhone 16 Pro Max", |
|
"iPhone17,3": "iPhone 16", |
|
"iPhone17,4": "iPhone 16 Plus", |
|
"iPhone17,5": "iPhone 16e", |
|
"iPhone2,1": "iPhone 3GS", |
|
"iPhone3,1": "iPhone 4", |
|
"iPhone3,2": "iPhone 4", |
|
"iPhone3,3": "iPhone 4", |
|
"iPhone4,1": "iPhone 4S", |
|
"iPhone5,1": "iPhone 5", |
|
"iPhone5,2": "iPhone 5", |
|
"iPhone5,3": "iPhone 5C", |
|
"iPhone5,4": "iPhone 5C", |
|
"iPhone6,1": "iPhone 5S", |
|
"iPhone6,2": "iPhone 5S", |
|
"iPhone7,1": "iPhone 6 Plus", |
|
"iPhone7,2": "iPhone 6", |
|
"iPhone8,1": "iPhone 6s", |
|
"iPhone8,2": "iPhone 6s Plus", |
|
"iPhone8,4": "iPhone SE", |
|
"iPhone9,1": "iPhone 7", |
|
"iPhone9,2": "iPhone 7 Plus", |
|
"iPhone9,3": "iPhone 7", |
|
"iPhone9,4": "iPhone 7 Plus", |
|
"iPod1,1": "1st Gen iPod", |
|
"iPod2,1": "2nd Gen iPod", |
|
"iPod3,1": "3rd Gen iPod", |
|
"iPod4,1": "4th Gen iPod", |
|
"iPod5,1": "5th Gen iPod", |
|
"iPod7,1": "6th Gen iPod", |
|
"iPod9,1": "7th Gen iPod", |
|
"x86_64": "iPhone Simulator", |
|
} |
|
|
|
|
|
CACHE_FILE = os.path.join( |
|
os.path.dirname(os.path.abspath(__file__)), "android_device_cache.json" |
|
) |
|
android_device_cache = {} |
|
|
|
|
|
|
|
def load_cache(): |
|
global android_device_cache |
|
try: |
|
if os.path.exists(CACHE_FILE): |
|
with open(CACHE_FILE, "r") as f: |
|
android_device_cache = json.load(f) |
|
print(f"Loaded {len(android_device_cache)} Android device names from cache") |
|
except Exception as e: |
|
print(f"Error loading Android device cache: {str(e)}") |
|
android_device_cache = {} |
|
|
|
|
|
|
|
def save_cache(): |
|
try: |
|
with open(CACHE_FILE, "w") as f: |
|
json.dump(android_device_cache, f, indent=2) |
|
except Exception as e: |
|
print(f"Error saving Android device cache: {str(e)}") |
|
|
|
|
|
|
|
load_cache() |
|
|
|
|
|
@lru_cache(maxsize=1024) |
|
def get_device_name(manufacturer, device_id, default_device_name): |
|
""" |
|
Get the normalized device name from a device ID like iPad16,1 |
|
|
|
Args: |
|
device_id (str): The device identifier (e.g., iPad16,1) |
|
|
|
Returns: |
|
str: The normalized device name without connectivity info |
|
""" |
|
|
|
if manufacturer == "Apple": |
|
return apple_device_mapping.get(device_id, default_device_name) |
|
else: |
|
return get_android_model_name(manufacturer, device_id) |
|
|
|
|
|
def get_android_model_name(manufacturer, model): |
|
""" |
|
Get a user-friendly Android device name from cache or GitHub repository |
|
|
|
Args: |
|
manufacturer (str): Device manufacturer |
|
model (str): Device model |
|
|
|
Returns: |
|
str: User-friendly device name, or original model if not found |
|
""" |
|
|
|
|
|
|
|
cache_key = f"{manufacturer.lower()}:{model.lower()}" |
|
|
|
|
|
if cache_key in android_device_cache: |
|
|
|
return android_device_cache[cache_key] |
|
|
|
|
|
repo_url = "https://raw.githubusercontent.com/openhoangnc/android_model_name/main" |
|
|
|
|
|
if not manufacturer: |
|
|
|
return model |
|
|
|
first_letter = manufacturer[0].lower() |
|
safe_manufacturer = quote(manufacturer.lower()) |
|
safe_model = quote(model.replace("/", "-").lower()) if model else "" |
|
|
|
|
|
query_url = f"{repo_url}/{first_letter}/{safe_manufacturer}/{safe_model}" |
|
|
|
try: |
|
|
|
response = requests.get(query_url, timeout=3) |
|
if response.status_code == 200: |
|
device_name = response.text.strip() |
|
|
|
android_device_cache[cache_key] = device_name |
|
|
|
if len(android_device_cache) % 10 == 0: |
|
save_cache() |
|
return device_name |
|
return model |
|
except Exception as e: |
|
print(f"Error fetching Android model name: {str(e)}") |
|
return model |
|
|
|
|
|
|
|
import atexit |
|
|
|
atexit.register(save_cache) |
|
|