Files
hunli/hunliji-api/visit/device_names.go
2026-08-04 10:26:00 +08:00

250 lines
7.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package visit
import (
"strings"
"unicode"
)
// friendlyAndroidName 将 UA 中的型号码映射为可读名称(品牌 + 营销名/型号)
func friendlyAndroidName(model string) string {
model = strings.TrimSpace(model)
if model == "" {
return "Android"
}
key := strings.ToUpper(model)
key = strings.ReplaceAll(key, " ", "")
if name, ok := androidModelNames[key]; ok {
return name
}
// 部分型号带前缀品牌词
if name, ok := androidModelNames[strings.ToUpper(strings.TrimSpace(model))]; ok {
return name
}
brand, rest := detectAndroidBrand(model)
if brand != "" {
if rest == "" || strings.EqualFold(rest, brand) {
return brand
}
// 已是「Xiaomi 14」这类可读名
if looksHumanDeviceName(model) {
if !strings.HasPrefix(model, brand) && !strings.Contains(model, brand) {
return brand + " " + model
}
return model
}
return brand + " " + rest
}
if looksHumanDeviceName(model) {
return model
}
return model
}
func looksHumanDeviceName(s string) bool {
hasLetter := false
hasSpaceOrCJK := false
for _, r := range s {
if unicode.Is(unicode.Han, r) {
return true
}
if r == ' ' {
hasSpaceOrCJK = true
}
if unicode.IsLetter(r) {
hasLetter = true
}
}
// Pixel 7 / Nexus 5X 等
return hasLetter && hasSpaceOrCJK
}
func detectAndroidBrand(model string) (brand, rest string) {
m := strings.TrimSpace(model)
upper := strings.ToUpper(m)
// 显式品牌前缀
prefixes := []struct {
prefix string
brand string
}{
{"HUAWEI ", "华为"},
{"HONOR ", "荣耀"},
{"XIAOMI ", "小米"},
{"REDMI ", "红米"},
{"OPPO ", "OPPO"},
{"VIVO ", "vivo"},
{"SAMSUNG ", "三星"},
{"ONEPLUS ", "一加"},
{"REALME ", "realme"},
{"MEIZU ", "魅族"},
{"GOOGLE ", "Google"},
{"PIXEL ", "Google"},
}
for _, p := range prefixes {
if strings.HasPrefix(upper, strings.ToUpper(p.prefix)) {
return p.brand, strings.TrimSpace(m[len(p.prefix):])
}
}
switch {
case strings.HasPrefix(upper, "SM-"), strings.HasPrefix(upper, "GT-"), strings.HasPrefix(upper, "SCH-"):
return "三星", m
case strings.HasPrefix(upper, "RMX"):
return "realme", m
case strings.HasPrefix(upper, "CPH"), strings.HasPrefix(upper, "PGFM"), strings.HasPrefix(upper, "PGBM"),
strings.HasPrefix(upper, "PGEM"), strings.HasPrefix(upper, "PHN"), strings.HasPrefix(upper, "PHW"),
strings.HasPrefix(upper, "PJU"), strings.HasPrefix(upper, "PJD"):
return "OPPO", m
case strings.HasPrefix(upper, "V2"), strings.HasPrefix(upper, "V1"), strings.HasPrefix(upper, "V3"):
// vivo / iQOO 国内型号多为 VxxxxA
if len(upper) >= 5 && unicode.IsDigit(rune(upper[1])) {
return "vivo", m
}
case strings.HasPrefix(upper, "NE2"), strings.HasPrefix(upper, "LE2"), strings.HasPrefix(upper, "KB2"),
strings.HasPrefix(upper, "PHB"), strings.HasPrefix(upper, "PHP"), strings.HasPrefix(upper, "CPH24"),
strings.HasPrefix(upper, "ONEPLUS"):
return "一加", m
case strings.HasPrefix(upper, "M20"), strings.HasPrefix(upper, "M21"), strings.HasPrefix(upper, "220"),
strings.HasPrefix(upper, "221"), strings.HasPrefix(upper, "222"), strings.HasPrefix(upper, "230"),
strings.HasPrefix(upper, "231"), strings.HasPrefix(upper, "240"), strings.HasPrefix(upper, "241"),
strings.HasPrefix(upper, "MI "), strings.HasPrefix(upper, "MI-"):
return "小米", m
case strings.Contains(upper, "REDMI"):
return "红米", m
case strings.HasSuffix(upper, "-AN00"), strings.HasSuffix(upper, "-AN10"), strings.HasSuffix(upper, "-AL00"),
strings.HasSuffix(upper, "-AL10"), strings.HasSuffix(upper, "-TL00"), strings.HasSuffix(upper, "-LND"):
// 华为/荣耀鸿蒙型号XXX-AN00
if isHonorModel(upper) {
return "荣耀", m
}
return "华为", m
case strings.HasPrefix(upper, "PIXEL"):
return "Google", m
case strings.HasPrefix(upper, "NEXUS"):
return "Google", m
}
return "", m
}
func isHonorModel(upper string) bool {
honor := []string{
"ANY-", "REP-", "FNE-", "FRI-", "ANN-", "ALA-", "BRT-", "SDY-", "ELP-",
"VER-", "MAA-", "REA-", "NTP-", "GIA-", "CLS-", "DIO-", "LGE-", "CRT-",
}
for _, p := range honor {
if strings.HasPrefix(upper, p) {
return true
}
}
return false
}
// 常见国内机型营销名(可持续补充;未命中仍走品牌+型号)
var androidModelNames = map[string]string{
// 三星
"SM-S9180": "三星 Galaxy S23 Ultra",
"SM-S9160": "三星 Galaxy S23+",
"SM-S9110": "三星 Galaxy S23",
"SM-S9280": "三星 Galaxy S24 Ultra",
"SM-S9260": "三星 Galaxy S24+",
"SM-S9210": "三星 Galaxy S24",
"SM-S9380": "三星 Galaxy S25 Ultra",
"SM-S9080": "三星 Galaxy S22 Ultra",
"SM-S9010": "三星 Galaxy S22",
"SM-G9980": "三星 Galaxy S21 Ultra",
"SM-G9910": "三星 Galaxy S21",
"SM-F9460": "三星 Galaxy Z Fold5",
"SM-F7310": "三星 Galaxy Z Flip5",
"SM-A5460": "三星 Galaxy A54",
"SM-A5560": "三星 Galaxy A55",
// 小米 / 红米
"24031PN0DC": "小米 14",
"23127PN0CC": "小米 14",
"2211133C": "小米 13",
"2210132C": "小米 13 Pro",
"2201123C": "小米 12",
"2201122C": "小米 12 Pro",
"M2011K2C": "小米 11",
"M2007J1SC": "小米 10 至尊纪念版",
"M2007J17C": "小米 10 青春版",
"2311DRK48C": "红米 K70",
"23113RKC6C": "红米 K70 Pro",
"23013RK75C": "红米 K60",
"22041216C": "红米 K50",
"24117RK2CC": "红米 K80",
"23078RKD5C": "红米 Note 12 Turbo",
"2312DRA50C": "红米 Note 13 Pro",
// 华为
"NOH-AN00": "华为 Mate 40 Pro",
"NOH-AL10": "华为 Mate 40 Pro",
"OCE-AN10": "华为 Mate 40",
"ANA-AN00": "华为 P40",
"ELS-AN00": "华为 P40 Pro",
"BRA-AL00": "华为 P60",
"ALN-AL00": "华为 Mate 60",
"ALN-AL80": "华为 Mate 60 Pro",
"LNA-AL00": "华为 Mate X5",
"ALT-AL10": "华为 Mate 70",
"PLA-AL10": "华为 Mate 70 Pro",
"ADT-AL00": "华为 Pura 70",
"ADY-AL00": "华为 Pura 70 Pro",
// 荣耀
"ANY-AN00": "荣耀 Magic5",
"REP-AN00": "荣耀 Magic5 Pro",
"FNE-AN00": "荣耀 90",
"FRI-AN00": "荣耀 Magic6",
"BVL-AN16": "荣耀 Magic6 Pro",
"MAA-AN10": "荣耀 200",
"CLK-AN00": "荣耀 100",
// OPPO
"PGEM10": "OPPO Find X6 Pro",
"PGFM10": "OPPO Find X6",
"PGBM10": "OPPO Find N2",
"PHN110": "OPPO Find X7 Ultra",
"PHY110": "OPPO Find X7",
"CPH2473": "OPPO Find X5 Pro",
"PJU110": "OPPO Reno12",
"PJV110": "OPPO Reno12 Pro",
// vivo / iQOO
"V2254A": "vivo X90 Pro+",
"V2241A": "vivo X90",
"V2227A": "vivo X90 Pro",
"V2309A": "vivo X100",
"V2324A": "vivo X100 Pro",
"V2307A": "iQOO 11",
"V2243A": "iQOO 10",
"V2329A": "iQOO 12",
"V2055A": "vivo S9",
"V2183A": "vivo S15",
// 一加
"PHB110": "一加 11",
"CPH2449": "一加 11",
"PJE110": "一加 12",
"PHP110": "一加 Ace 2",
"NE2210": "一加 10 Pro",
// realme
"RMX3562": "realme GT Neo3",
"RMX3370": "realme GT Neo2",
"RMX3706": "realme GT5",
"RMX3888": "realme GT5 Pro",
// Google
"PIXEL 9 PRO": "Google Pixel 9 Pro",
"PIXEL 9": "Google Pixel 9",
"PIXEL 8 PRO": "Google Pixel 8 Pro",
"PIXEL 8": "Google Pixel 8",
"PIXEL 7 PRO": "Google Pixel 7 Pro",
"PIXEL 7": "Google Pixel 7",
"PIXEL 6 PRO": "Google Pixel 6 Pro",
"PIXEL 6": "Google Pixel 6",
}