package apple import ( "encoding/json" "strconv" "strings" "time" ) type ProductMapping struct { DurationDays int64 `json:"durationDays"` Tier string `json:"tier"` Description string `json:"description"` PriceText string `json:"priceText"` SubscribeId int64 `json:"subscribeId"` } type ProductMap struct { Items map[string]ProductMapping `json:"iapProductMap"` } func ParseProductMap(customData string) (*ProductMap, error) { if customData == "" { return &ProductMap{Items: map[string]ProductMapping{}}, nil } var obj ProductMap if err := json.Unmarshal([]byte(customData), &obj); err != nil { return &ProductMap{Items: map[string]ProductMapping{}}, nil } if obj.Items == nil { obj.Items = map[string]ProductMapping{} } return &obj, nil } func CalcExpire(start time.Time, days int64) time.Time { if days <= 0 { return time.UnixMilli(0) } return start.Add(time.Duration(days) * 24 * time.Hour) } // ParsedProduct holds the result of parsing an Apple product ID. type ParsedProduct struct { Unit string // "Day", "Month", "Year" Quantity int64 } // ParseProductIdDuration extracts time unit and quantity from Apple product IDs. // e.g. "com.app.vip.day30" -> {Unit: "Day", Quantity: 30} func ParseProductIdDuration(productId string) *ParsedProduct { pid := strings.ToLower(productId) parts := strings.Split(pid, ".") for i := len(parts) - 1; i >= 0; i-- { p := parts[i] var unit string switch { case strings.HasPrefix(p, "day"): unit = "Day" p = p[len("day"):] case strings.HasPrefix(p, "month"): unit = "Month" p = p[len("month"):] case strings.HasPrefix(p, "year"): unit = "Year" p = p[len("year"):] default: continue } digits := p for j := 0; j < len(digits); j++ { if digits[j] < '0' || digits[j] > '9' { digits = digits[:j] break } } if q, e := strconv.ParseInt(digits, 10, 64); e == nil && q > 0 { return &ParsedProduct{Unit: unit, Quantity: q} } } return nil }