package tf import ( "fmt" "net/http" "stat/common/log" "strings" "github.com/PuerkitoBio/goquery" ) type Result struct { Valid bool Desc string AppName string AppIcon string } // address: https://testflight.apple.com/join/whsnQnSb // https://testflight.apple.com/join/M3cBOOzR func CheckTFValid(address string) (*Result, error) { var checkResult Result req, err := http.NewRequest("GET", address, nil) if err != nil { log.Warn("CheckTFValid newRequest", log.Any("address", address), log.E(err)) checkResult.Desc = err.Error() return nil, err } req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9") req.Header.Add("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6") req.Header.Add("Cache-Control", "no-cache") req.Header.Add("Connection", "keep-alive") req.Header.Add("Pragma", "no-cache") req.Header.Add("Sec-Fetch-Dest", "document") req.Header.Add("Sec-Fetch-Mode", "navigate") req.Header.Add("Sec-Fetch-Site", "none") req.Header.Add("Sec-Fetch-User", "?1") req.Header.Add("Upgrade-Insecure-Requests", "1") req.Header.Add("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Mobile/15E148 Safari/604.1") res, err := http.DefaultClient.Do(req) if err != nil { log.Warn("CheckTFValid Client Do", log.Any("address", address), log.E(err)) return nil, err } defer func() { _ = res.Body.Close() }() //不为200 肯定出问题了 if res.StatusCode != http.StatusOK { checkResult.Desc = fmt.Sprintf("HttpStatus:%d", res.StatusCode) return &checkResult, nil } //状态为200,解析内容 doc, err := goquery.NewDocumentFromReader(res.Body) if err != nil { log.Warn("CheckTFValid NewDocumentFromReader err", log.Any("address", address), log.E(err)) return &checkResult, err } valid, desc := checkValid(doc) if !valid { checkResult.Desc = desc return &checkResult, nil } appName := getAppName(doc) appIcon := getAppIcon(doc) checkResult.Valid = true checkResult.AppName = appName checkResult.AppIcon = appIcon return &checkResult, nil } func checkValid(doc *goquery.Document) (bool, string) { foundStartTesting := false doc.Find("a").EachWithBreak(func(i int, s *goquery.Selection) bool { text := strings.TrimSpace(s.Text()) if text == "Start Testing" || text == "开始测试" { foundStartTesting = true return false } return true }) if foundStartTesting { return true, "" //TF包有效 } betaStatus := "" doc.Find(".beta-status").EachWithBreak(func(i int, s *goquery.Selection) bool { betaStatus = strings.TrimSpace(s.Text()) return false }) if betaStatus == "" { return true, "" } if strings.Contains(betaStatus, "install TestFlight") || strings.Contains(betaStatus, "安装 TestFlight") { return true, "" } //TODO: 这里还需要测试,目前来看,出现betaStatus就是无效的 return false, betaStatus } func getAppName(doc *goquery.Document) string { var appName string doc.Find("title").EachWithBreak(func(i int, selection *goquery.Selection) bool { //加入 Beta 版“原创短视频” - TestFlight - Apple //Join the READ-O beta - TestFlight - Apple v := strings.TrimSpace(selection.Text()) rawLen := len(v) v = strings.TrimPrefix(v, "加入 Beta 版") v = strings.TrimPrefix(v, "Join the") v = strings.TrimSuffix(v, "beta - TestFlight - Apple") v = strings.TrimSuffix(v, "- TestFlight - Apple") v = strings.TrimSpace(v) v = strings.TrimLeft(v, "“") v = strings.TrimRight(v, "”") currLen := len(v) if rawLen == currLen { return true } appName = v return false }) return appName } func getAppIcon(doc *goquery.Document) string { var iconUrl string doc.Find(".app-icon.callout.ios").EachWithBreak(func(i int, selection *goquery.Selection) bool { nodes := selection.Nodes if len(nodes) == 0 { return true } attrs := selection.Nodes[0].Attr for _, attr := range attrs { if attr.Key == "style" { href := attr.Val href = strings.TrimPrefix(href, "background-image: url(") href = strings.TrimSuffix(href, ");") if len(href) != len(attr.Val) { iconUrl = href return false } } } return true }) return iconUrl }