package huashijie_api import ( "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "os" "strconv" "strings" "time" ) var XIAOMI_MODELS = []string{ "2107119DC", "23116PN5BC", "23124RN87C", "24031PN0DC", "24072PX77C", "24074RPD2C", "M1804E4A", "M1810E5GG", "M2001J1C", "M2002J9E", "MDE5", } var Logger = log.New(os.Stdout, "[huashijie_api] ", log.Ldate|log.Ltime|log.Lmsgprefix) func EnsureConnection(client http.Client) { // https://app.huashijie.art/api/update/checkUpdate req, err := http.NewRequest("GET", "https://app.huashijie.art/api/update/checkUpdate", nil) if err != nil { panic(err) } req.Header.Add("Referer", "https://app.huashijie.art/") req.Header.Add("User-Agent", "Dalvik/2.1.0 (Linux; U; Android 9; MI 8 SE MIUI/V12.0.2.0.PEBCNXM)") resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { panic(err) } text := string(body) Logger.Println(text) if !strings.Contains(text, "update_ver_code") { panic("NotImplementedError: " + text) } // 125277547 body, r_status := GetWorkDetailResponse(client, "125277547") if r_status != 200 { Logger.Println("HTTP status code:", r_status, "body:", string(body)) panic("HTTP status code: " + strconv.Itoa(r_status)) } var r_json map[string]interface{} if err := json.Unmarshal(body, &r_json); err != nil { Logger.Println("failed to parse JSON:", string(body), "error:", err) panic("failed to parse JSON: " + string(body)) } // check if 'status' in r_json if status, ok := r_json["status"]; ok { switch status := status.(type) { case float64: if status == 1 { // OK Logger.Println("len(body):", len(body), "->", string(body[:256]), "...OK") return } } } Logger.Println("JSON:", string(body)) panic("assertion failed: status == 1") } var cur_fake_user_id = -1 var cur_fake_user_left = time.Now() func GetWorkDetailResponse(client http.Client, work_id string) ([]byte, int) { endpoint := "https://app.huashijie.art/" if os.Getenv("HSJ_ENDPOINT") == "pandapaint" { endpoint = "https://api.pandapaint.net/" } req, err := http.NewRequest("GET", endpoint+"api/work/detailV2", nil) if err != nil { panic(err) } visitorId := "-1" token := "" if os.Getenv("HSJ_USERID") != "" { visitorId = os.Getenv("HSJ_USERID") if visitorId == "random" { if cur_fake_user_left.Before(time.Now()) { // rotate [1, 15] minutes cur_fake_user_left = time.Now().Add(time.Duration(rand.Intn(15)) * time.Minute) // random [30000000, 40000000] cur_fake_user_id = rand.Intn(40000000-30000000) + 30000000 } visitorId = fmt.Sprintf("%d", cur_fake_user_id) } // fake token = md5(visitorId + "huashijie") // md5hash := md5.New() // md5hash.Write([]byte(visitorId + "huashijie")) // token = fmt.Sprintf("%x", md5hash.Sum(nil)) Logger.Println("USERID:", visitorId, "token:", token, "left", time.Until(cur_fake_user_left)) } p := "" p += "visitorId=" + visitorId p += "&workId=" + work_id p += "&cur_user_id=" + visitorId p += "&platform=android" os_version := rand.Intn(34-28) + 28 p += fmt.Sprintf("&os_version=%d", os_version) if os.Getenv("HSJ_ENDPOINT") == "pandapaint" { p += "&version_code=168" } else { p += "&version_code=241" } p += "&device_brand=xiaomi" device_model := XIAOMI_MODELS[rand.Intn(len(XIAOMI_MODELS))] p += "&device_model=" + device_model p += "&token=" + token if os.Getenv("HSJ_ENDPOINT") == "pandapaint" { p += "&channel=Panda.main" } else { p += "&channel=main" } headers := map[string][]string{ "Referer": {endpoint}, "User-Agent": {"okhttp/3.12.0"}, } for k, v := range headers { req.Header[k] = v } // req.URL.RawQuery = q.Encode() req.URL.RawQuery = p resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { panic(err) } return body, resp.StatusCode }