Files
perennial 4cffa928b8 wip: responsive resolution for artwork thumbnails
core/mangaseries: inline comments

core/types: comment out debug statements
2024-10-29 17:38:04 +11:00

118 lines
3.5 KiB
Go

package core
import (
"fmt"
"net/http"
"strings"
"time"
"codeberg.org/vnpower/pixivfe/v2/audit"
"codeberg.org/vnpower/pixivfe/v2/i18n"
"codeberg.org/vnpower/pixivfe/v2/server/session"
"github.com/goccy/go-json"
)
/*
TODO: occasionally, Pixiv feels like returning an HTML response instead of the expected JSON,
causing an unmarshalling error on our end and forcing a refresh by the user
as a (super secret and hardcoded) workaround, we implement automatic retries to
eventually get the JSON response we need (usually only takes a single retry)
from qualitative testing, it seems like the interval between requests doesn't actually matter,
just the fact that we send a second request is enough
*/
const (
maxRetries = 5
retryDelay = 10 * time.Millisecond
)
type Ranking struct {
Contents []RankingContent `json:"contents"`
Mode string `json:"mode"`
Content string `json:"content"`
Page int `json:"page"`
RankTotal int `json:"rank_total"`
CurrentDate string `json:"date"`
PrevDateRaw json.RawMessage `json:"prev_date"`
NextDateRaw json.RawMessage `json:"next_date"`
PrevDate string
NextDate string
}
type RankingContent struct {
Title string `json:"title"`
Thumbnail string `json:"url"`
Thumbnails Thumbnails
Pages int `json:"illust_page_count,string"`
ArtistName string `json:"user_name"`
ArtistAvatar string `json:"profile_img"`
ID int `json:"illust_id"`
ArtistID int `json:"user_id"`
Rank int `json:"rank"`
IllustType int `json:"illust_type,string"`
XRestrict int // zero field for template
}
// see core/types.go for the Ranking struct
func GetRanking(auditor *audit.Auditor, r *http.Request, mode, content, date, page string) (Ranking, error) {
// log.Printf("GetRanking called with mode: %s, content: %s, date: %s, page: %s", mode, content, date, page)
URL := GetRankingURL(mode, content, date, page)
// log.Printf("Ranking URL: %s", URL)
var ranking Ranking
var lastErr error
for attempt := 0; attempt < maxRetries; attempt++ {
i18n.Sprintf("Attempt %d of %d", attempt+1, maxRetries)
resp, err := API_GET(r.Context(), auditor, URL, "", r.Header)
if err != nil {
i18n.Errorf("API_GET error: %v", err)
return ranking, err
}
proxiedResp, err := session.ProxyImageUrl(r, resp.Body)
if err != nil {
return ranking, err
}
err = json.Unmarshal([]byte(proxiedResp), &ranking)
if err == nil {
i18n.Sprintf("JSON unmarshalling successful on attempt %d", attempt+1)
lastErr = nil // Reset lastErr on successful unmarshalling
break
}
lastErr = err
i18n.Errorf("JSON unmarshalling error on attempt %d: %v", attempt+1, err)
if attempt < maxRetries-1 {
i18n.Sprintf("Retrying in %v", retryDelay)
time.Sleep(retryDelay)
}
}
if lastErr != nil {
// NOTE: This shouldn't happen; indicative of a different issue
i18n.Errorf("All attempts failed. Last error: %v", lastErr)
return ranking, lastErr
}
ranking.PrevDate = strings.ReplaceAll(string(ranking.PrevDateRaw[:]), "\"", "")
ranking.NextDate = strings.ReplaceAll(string(ranking.NextDateRaw[:]), "\"", "")
// Populate thumbnails
if err := ranking.PopulateThumbnails(auditor); err != nil {
return ranking, fmt.Errorf("failed to populate thumbnails for ranking: %w", err)
}
// log.Printf("GetRanking completed successfully. PrevDate: %s, NextDate: %s", ranking.PrevDate, ranking.NextDate)
return ranking, nil
}