package falseknees import ( "context" "errors" "fmt" "io/ioutil" "math/rand" "net/http" "regexp" "strconv" "time" ) var ( updateInterval = time.Minute * 30 baseURL = "https://www.falseknees.com/" currentRe = regexp.MustCompile(`window\.location\.href.+"(.+)\.html"`) imageRe = regexp.MustCompile(`src="(imgs.+\.png)".+title="(.+)"`) current int lastUpdate time.Time ) // Comic is a FalseKnees comic type Comic struct { Num int Title string Img string } // Comic returns a specific Comic func (c *Client) Comic(ctx context.Context, num int) (*Comic, error) { return c.comic(ctx, num) } // Current returns the current Comic func (c *Client) Current(ctx context.Context) (*Comic, error) { if err := c.updateCurrent(ctx); err != nil { return nil, err } return c.Comic(ctx, current) } // Random returns a random Comic func (c *Client) Random(ctx context.Context) (*Comic, error) { if err := c.updateCurrent(ctx); err != nil { return nil, err } rand.Seed(time.Now().UnixNano()) return c.Comic(ctx, rand.Intn(current)+1) } func (c *Client) updateCurrent(ctx context.Context) error { now := time.Now() if !lastUpdate.IsZero() && lastUpdate.After(now.Add(-updateInterval)) { return nil } lastUpdate = now u := fmt.Sprintf("%sindex.html", baseURL) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return err } resp, err := c.http.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("could not get page for index: %s", resp.Status) } body, err := ioutil.ReadAll(resp.Body) if err != nil { return err } defer resp.Body.Close() match := currentRe.FindStringSubmatch(string(body)) if len(match) == 0 { return errors.New("could not find current comic") } curr, err := strconv.Atoi(match[1]) if err != nil { return err } current = curr return nil } func (c *Client) comic(ctx context.Context, num int) (*Comic, error) { u := fmt.Sprintf("%s%d.html", baseURL, num) req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) if err != nil { return nil, err } resp, err := c.http.Do(req) if err != nil { return nil, err } if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("could not get page for comic %d: %s", num, resp.Status) } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } defer resp.Body.Close() match := imageRe.FindStringSubmatch(string(body)) if len(match) == 0 { return nil, fmt.Errorf("could not find comic #%d", num) } return &Comic{ Num: num, Title: match[2], Img: fmt.Sprintf("%s%s", baseURL, match[1]), }, nil }