|
@@ -41,6 +41,26 @@ type LandingArtworks struct {
|
|
|
RecommendByTags []RecommendedTags
|
|
|
}
|
|
|
|
|
|
+type Pages struct {
|
|
|
+ Pixivision []Pixivision `json:"pixivision"`
|
|
|
+ Follow []int `json:"follow"`
|
|
|
+ Recommended RecommendedSection `json:"recommend"`
|
|
|
+ RecommendedByTag []RecommendByTag `json:"recommendByTag"`
|
|
|
+ // Commented out fields that aren't currently implemented in the frontend
|
|
|
+ // EditorRecommended []any `json:"editorRecommend"`
|
|
|
+ // UserRecommended []any `json:"recommendUser"`
|
|
|
+ // Commission []any `json:"completeRequestIds"`
|
|
|
+}
|
|
|
+
|
|
|
+type RecommendedSection struct {
|
|
|
+ IDs []string `json:"ids"`
|
|
|
+}
|
|
|
+
|
|
|
+type RecommendByTag struct {
|
|
|
+ Name string `json:"tag"`
|
|
|
+ IDs []string `json:"ids"`
|
|
|
+}
|
|
|
+
|
|
|
// Constants for calling GetNewestFromFollowing when len(followIDs) == 0
|
|
|
const (
|
|
|
// FollowingMode = "all"
|
|
@@ -57,39 +77,51 @@ var landingToRankingMode = map[string]string{
|
|
|
//
|
|
|
// It fetches raw data from the landing URL, parses the JSON response, and populates the LandingArtworks struct.
|
|
|
func GetLanding(auditor *audit.Auditor, r *http.Request, mode string, isLoggedIn bool) (*LandingArtworks, error) {
|
|
|
+ ctx := &RequestContext{auditor: auditor, request: r}
|
|
|
URL := GetLandingURL(mode)
|
|
|
|
|
|
- resp, err := fetchLandingData(auditor, r, URL)
|
|
|
+ resp, err := API_GET_UnwrapJson(ctx.request.Context(), ctx.auditor, URL, "", ctx.request.Header)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- artworks, err := parseArtworks(resp)
|
|
|
+ resp, err = session.ProxyImageUrl(ctx.request, resp)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- pages, err := parsePages(resp)
|
|
|
+ if !gjson.Valid(resp) {
|
|
|
+ return nil, i18n.Errorf("Invalid JSON: %v", resp)
|
|
|
+ }
|
|
|
+
|
|
|
+ artworks, err := parseArtworks(resp)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
+ var pages Pages
|
|
|
+ pagesStr := gjson.Get(resp, "page").String()
|
|
|
+
|
|
|
+ if err := json.Unmarshal([]byte(pagesStr), &pages); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
landing := LandingArtworks{
|
|
|
Pixivision: pages.Pixivision,
|
|
|
}
|
|
|
|
|
|
// If the user is logged in, populate personalized sections
|
|
|
if isLoggedIn {
|
|
|
- landing.Following, err = populateFollowing(auditor, r, mode, pages.Follow, artworks)
|
|
|
+ landing.Following, err = ctx.populateFollowing(mode, pages.Follow, artworks)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- landing.RecommendByTags = populateRecommendedByTags(pages.RecommendedByTags, artworks)
|
|
|
- landing.Recommended = populateRecommended(pages.Recommended.IDs, artworks)
|
|
|
+ landing.RecommendByTags = populateRecommendedByTags(pages.RecommendedByTag, artworks)
|
|
|
+ landing.Recommended = populateArtworks(pages.Recommended.IDs, artworks)
|
|
|
}
|
|
|
|
|
|
- landing.Rankings, err = fetchRankings(auditor, r, mode)
|
|
|
+ landing.Rankings, err = ctx.fetchRankings(mode)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
@@ -97,33 +129,8 @@ func GetLanding(auditor *audit.Auditor, r *http.Request, mode string, isLoggedIn
|
|
|
return &landing, nil
|
|
|
}
|
|
|
|
|
|
-// fetchLandingData retrieves the landing data from the specified URL and validates its JSON format.
|
|
|
-//
|
|
|
-// Returns the raw JSON response as a string if valid.
|
|
|
-func fetchLandingData(auditor *audit.Auditor, r *http.Request, URL string) (string, error) {
|
|
|
- resp, err := API_GET_UnwrapJson(r.Context(), auditor, URL, "", r.Header)
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
- }
|
|
|
-
|
|
|
- resp, err = session.ProxyImageUrl(r, resp)
|
|
|
- if err != nil {
|
|
|
- return "", err
|
|
|
- }
|
|
|
-
|
|
|
- if !gjson.Valid(resp) {
|
|
|
- return "", i18n.Errorf("Invalid JSON: %v", resp)
|
|
|
- }
|
|
|
-
|
|
|
- // auditor.SugaredLogger.Debugf("Landing page JSON response:\n%s\n", resp)
|
|
|
-
|
|
|
- return resp, nil
|
|
|
-}
|
|
|
-
|
|
|
// parseArtworks extracts artwork information from the "thumbnails.illust" field
|
|
|
// of the JSON response and maps them by their ID.
|
|
|
-//
|
|
|
-// This allows for quick lookup of artworks when populating various sections.
|
|
|
func parseArtworks(resp string) (map[string]ArtworkBrief, error) {
|
|
|
artworks := make(map[string]ArtworkBrief)
|
|
|
|
|
@@ -148,69 +155,33 @@ func parseArtworks(resp string) (map[string]ArtworkBrief, error) {
|
|
|
return artworks, nil
|
|
|
}
|
|
|
|
|
|
-// parsePages unmarshals the "page" field from the JSON response into a structured format.
|
|
|
-func parsePages(resp string) (*struct {
|
|
|
- Pixivision []Pixivision `json:"pixivision"`
|
|
|
- Follow []int `json:"follow"`
|
|
|
- Recommended struct {
|
|
|
- IDs []string `json:"ids"`
|
|
|
- } `json:"recommend"`
|
|
|
- RecommendedByTags []struct {
|
|
|
- Name string `json:"tag"`
|
|
|
- IDs []string `json:"ids"`
|
|
|
- } `json:"recommendByTag"`
|
|
|
-}, error,
|
|
|
-) {
|
|
|
- var pages struct {
|
|
|
- Pixivision []Pixivision `json:"pixivision"`
|
|
|
- Follow []int `json:"follow"`
|
|
|
- Recommended struct {
|
|
|
- IDs []string `json:"ids"`
|
|
|
- } `json:"recommend"`
|
|
|
- // Commented out fields that aren't currently implemented in the frontend
|
|
|
- // EditorRecommended []any `json:"editorRecommend"`
|
|
|
- // UserRecommended []any `json:"recommendUser"`
|
|
|
- // Commission []any `json:"completeRequestIds"`
|
|
|
- RecommendedByTags []struct {
|
|
|
- Name string `json:"tag"`
|
|
|
- IDs []string `json:"ids"`
|
|
|
- } `json:"recommendByTag"`
|
|
|
- }
|
|
|
-
|
|
|
- pagesStr := gjson.Get(resp, "page").String()
|
|
|
-
|
|
|
- if err := json.Unmarshal([]byte(pagesStr), &pages); err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- return &pages, nil
|
|
|
-}
|
|
|
-
|
|
|
// populateArtworks is a generic helper function that maps a slice of string IDs
|
|
|
// to their corresponding ArtworkBrief objects.
|
|
|
func populateArtworks(ids []string, artworks map[string]ArtworkBrief) []ArtworkBrief {
|
|
|
populated := make([]ArtworkBrief, 0, len(ids))
|
|
|
+
|
|
|
for _, id := range ids {
|
|
|
if artwork, exists := artworks[id]; exists {
|
|
|
populated = append(populated, artwork)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
return populated
|
|
|
}
|
|
|
|
|
|
// populateFollowing converts int IDs to strings and uses the generic helper.
|
|
|
//
|
|
|
// If followIDs is empty, it attempts population by calling GetNewestFromFollowing instead (pixiv moment).
|
|
|
-func populateFollowing(auditor *audit.Auditor, r *http.Request, mode string, followIDs []int, artworks map[string]ArtworkBrief) ([]ArtworkBrief, error) {
|
|
|
- // Call GetNewestFromFollowing with predefined mode and page
|
|
|
+func (ctx *RequestContext) populateFollowing(mode string, followIDs []int, artworks map[string]ArtworkBrief) ([]ArtworkBrief, error) {
|
|
|
if len(followIDs) == 0 {
|
|
|
- return GetNewestFromFollowing(auditor, r, mode, FollowingPage)
|
|
|
+ return GetNewestFromFollowing(ctx.auditor, ctx.request, mode, FollowingPage)
|
|
|
}
|
|
|
|
|
|
- stringIDs := make([]string, 0, len(followIDs))
|
|
|
- for _, id := range followIDs {
|
|
|
- stringIDs = append(stringIDs, fmt.Sprint(id))
|
|
|
+ stringIDs := make([]string, len(followIDs))
|
|
|
+ for i, id := range followIDs {
|
|
|
+ stringIDs[i] = fmt.Sprint(id)
|
|
|
}
|
|
|
+
|
|
|
return populateArtworks(stringIDs, artworks), nil
|
|
|
}
|
|
|
|
|
@@ -220,11 +191,7 @@ func populateRecommended(recommendedIDs []string, artworks map[string]ArtworkBri
|
|
|
}
|
|
|
|
|
|
// populateRecommendedByTags uses the generic helper for each tag's IDs.
|
|
|
-func populateRecommendedByTags(recommends []struct {
|
|
|
- Name string `json:"tag"`
|
|
|
- IDs []string `json:"ids"`
|
|
|
-}, artworks map[string]ArtworkBrief,
|
|
|
-) []RecommendedTags {
|
|
|
+func populateRecommendedByTags(recommends []RecommendByTag, artworks map[string]ArtworkBrief) []RecommendedTags {
|
|
|
recommendByTags := make([]RecommendedTags, 0, len(recommends))
|
|
|
|
|
|
for _, r := range recommends {
|
|
@@ -234,22 +201,17 @@ func populateRecommendedByTags(recommends []struct {
|
|
|
Artworks: artworksList,
|
|
|
})
|
|
|
}
|
|
|
+
|
|
|
return recommendByTags
|
|
|
}
|
|
|
|
|
|
// fetchRankings retrieves the current rankings based on the selected mode.
|
|
|
//
|
|
|
// It maps the landing page mode to the appropriate ranking mode and fetches the ranking data.
|
|
|
-func fetchRankings(auditor *audit.Auditor, r *http.Request, mode string) (Ranking, error) {
|
|
|
+func (ctx *RequestContext) fetchRankings(mode string) (Ranking, error) {
|
|
|
rankingMode, exists := landingToRankingMode[mode]
|
|
|
if !exists {
|
|
|
rankingMode = "daily"
|
|
|
}
|
|
|
-
|
|
|
- rankings, err := GetRanking(auditor, r, rankingMode, "illust", "", "1")
|
|
|
- if err != nil {
|
|
|
- return Ranking{}, err
|
|
|
- }
|
|
|
-
|
|
|
- return rankings, nil
|
|
|
+ return GetRanking(ctx.auditor, ctx.request, rankingMode, "illust", "", "1")
|
|
|
}
|