package utils import ( "encoding/json" "fmt" "net/http" "net/url" "os" "strconv" "time" "github.com/go-resty/resty/v2" ) // https://github.com/FlareSolverr/FlareSolverr#-requestget type Request struct { Cmd string `json:"cmd"` Url string `json:"url"` MaxTimeout int `json:"maxTimeout"` OnlyCookies bool `json:"returnOnlyCookies"` } type Cookie struct { Name string `json:"name"` Value string `json:"value"` Domain string `json:"domain"` Path string `json:"path"` Expires time.Time `json:"expires"` Size uint64 `json:"size"` HttpOnly bool `json:"httpOnly"` Secure bool `json:"secure"` Session bool `json:"session"` SameSite string `json:"sameSite"` } type Solution struct { Status int `json:"status"` Cookies []Cookie `json:"cookies"` Agent string `json:"userAgent"` } type Response struct { Solution Solution `json:"solution"` } func (c *Cookie) ToCookie() *http.Cookie { ss := http.SameSiteNoneMode switch c.SameSite { case "Lax": ss = http.SameSiteLaxMode case "Strict": ss = http.SameSiteStrictMode case "Default": ss = http.SameSiteDefaultMode } return &http.Cookie{ Name: c.Name, Value: c.Value, Domain: c.Domain, Path: c.Path, Expires: c.Expires, HttpOnly: c.HttpOnly, Secure: c.Secure, SameSite: ss, } } func (s *Solution) HttpCookies() []*http.Cookie { cookies := []*http.Cookie{} for i := range s.Cookies { cookies = append(cookies, s.Cookies[i].ToCookie()) } return cookies } const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3" const DEFAULT_TIMEOUT = 120 var ( solution *Solution = nil fs_url string = "" fs_timeout int = DEFAULT_TIMEOUT ) func Solve(target string) error { if fs_url == "" { return fmt.Errorf("flaresolver is not configured") } url, _ := url.JoinPath(fs_url, "/v1") response := Response{} client := resty.New() res, err := client.R(). SetBody(Request{ Cmd: "request.get", Url: target, MaxTimeout: fs_timeout * 100, OnlyCookies: true, }). Post(url) if err != nil { return fmt.Errorf("request failed: %s", err.Error()) } if res.StatusCode() != 200 { return fmt.Errorf("bad status code: %d", res.StatusCode()) } if err := json.Unmarshal(res.Body(), &response); err != nil { return fmt.Errorf("failed to parse body: %s", err.Error()) } solution = &response.Solution return nil } func GET(target string, no_retry ...bool) (*resty.Response, error) { client := resty.New() req := client.R() if solution != nil { req.SetCookies(solution.HttpCookies()) req.SetHeader("User-Agent", solution.Agent) } else { req.SetHeader("User-Agent", USER_AGENT) } res, err := req.Get(target) if err != nil { return nil, err } if res.StatusCode() != http.StatusForbidden { return res, err } if err = Solve(target); err != nil { return nil, err } if len(no_retry) == 0 { return GET(target) } return nil, fmt.Errorf("solution did not work") } func ReqSetup() { fs_url = os.Getenv("FLARESOLVER") timeout := os.Getenv("TIMEOUT") if timeout == "" { return } if to, err := strconv.Atoi(timeout); err != nil { fmt.Printf("failed to parse timeout: %s\n", err.Error()) } else if to <= 0 { fmt.Println("invalid timeout, timeout should be greater than zero") } else { return } fmt.Printf("using the default timeout instead (%d secs)\n", DEFAULT_TIMEOUT) fs_timeout = DEFAULT_TIMEOUT }