mirror of
https://codeberg.org/VnPower/PixivFE
synced 2024-12-06 19:16:23 +01:00
wip: responsive resolution for artwork thumbnails
core/mangaseries: inline comments core/types: comment out debug statements
This commit is contained in:
+26
-12
@@ -113,18 +113,13 @@ type ArtworkBrief struct {
|
||||
ArtistName string `json:"userName"`
|
||||
ArtistAvatar string `json:"profileImageUrl"`
|
||||
Thumbnail string `json:"url"`
|
||||
Thumbnails struct {
|
||||
Small string `json:"250x250"`
|
||||
Medium string `json:"360x360"`
|
||||
Large string `json:"540x540"`
|
||||
Master string `json:"1200x1200"`
|
||||
} `json:"urls"`
|
||||
Pages int `json:"pageCount"`
|
||||
XRestrict int `json:"xRestrict"`
|
||||
AiType int `json:"aiType"`
|
||||
Bookmarked any `json:"bookmarkData"`
|
||||
IllustType int `json:"illustType"`
|
||||
Tags []string `json:"tags"` // used by core/popular_search
|
||||
Thumbnails Thumbnails
|
||||
Pages int `json:"pageCount"`
|
||||
XRestrict int `json:"xRestrict"`
|
||||
AiType int `json:"aiType"`
|
||||
Bookmarked any `json:"bookmarkData"`
|
||||
IllustType int `json:"illustType"`
|
||||
Tags []string `json:"tags"` // used by core/popular_search
|
||||
}
|
||||
|
||||
type Illust struct {
|
||||
@@ -267,6 +262,15 @@ func GetRelatedArtworks(auditor *audit.Auditor, r *http.Request, id string) ([]A
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range body.Illusts {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
body.Illusts[id] = artwork
|
||||
}
|
||||
|
||||
return body.Illusts, nil
|
||||
}
|
||||
|
||||
@@ -381,6 +385,16 @@ func GetArtworkByID(auditor *audit.Auditor, r *http.Request, id string, full boo
|
||||
sort.Slice(recent[:], func(i, j int) bool {
|
||||
return numberGreaterThan(recent[i].ID, recent[j].ID)
|
||||
})
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range recent {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
recent[id] = artwork
|
||||
}
|
||||
|
||||
illust.RecentWorks = recent
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -39,6 +39,15 @@ func GetDiscoveryArtwork(auditor *audit.Auditor, r *http.Request, mode string) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range artworks {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
artworks[id] = artwork
|
||||
}
|
||||
|
||||
return artworks, nil
|
||||
}
|
||||
|
||||
@@ -108,6 +117,15 @@ func GetDiscoveryUsers(auditor *audit.Auditor, r *http.Request) ([]User, error)
|
||||
return nil, fmt.Errorf("error unmarshalling artworks in GetDiscoveryUser: %w", err)
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range artworks {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
artworks[id] = artwork
|
||||
}
|
||||
|
||||
// Extract and unmarshal novels
|
||||
novelData := gjson.Get(resp, "thumbnails.novel").Raw
|
||||
var novels []NovelBrief
|
||||
|
||||
@@ -99,6 +99,15 @@ func GetLanding(auditor *audit.Auditor, r *http.Request, mode string, isLoggedIn
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range artworks {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
artworks[id] = artwork
|
||||
}
|
||||
|
||||
var pages Pages
|
||||
pagesStr := gjson.Get(resp, "page").String()
|
||||
|
||||
|
||||
+30
-9
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
// MangaSeries represents the metadata of a manga series.
|
||||
type MangaSeries struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"userId"`
|
||||
@@ -18,7 +20,7 @@ type MangaSeries struct {
|
||||
Caption string `json:"caption"`
|
||||
Total int `json:"total"`
|
||||
ContentOrder any `json:"content_order"`
|
||||
URL string `json:"url"`
|
||||
Thumbnail string `json:"url"`
|
||||
CoverImageSl int `json:"coverImageSl"`
|
||||
FirstIllustID string `json:"firstIllustId"`
|
||||
LatestIllustID string `json:"latestIllustId"`
|
||||
@@ -29,6 +31,7 @@ type MangaSeries struct {
|
||||
IsNotifying bool `json:"isNotifying"`
|
||||
}
|
||||
|
||||
// MangaSeriesContent encapsulates the content details of a manga series.
|
||||
type MangaSeriesContent struct {
|
||||
Series []struct {
|
||||
WorkID string `json:"workId"`
|
||||
@@ -45,6 +48,7 @@ type MangaSeriesContent struct {
|
||||
Brief MangaSeries
|
||||
}
|
||||
|
||||
// GetMangaSeriesContentByID retrieves the content of a manga series by its ID and page number.
|
||||
func GetMangaSeriesContentByID(auditor *audit.Auditor, r *http.Request, id string, page int) (MangaSeriesContent, error) {
|
||||
var series_content MangaSeriesContent
|
||||
|
||||
@@ -60,31 +64,48 @@ func GetMangaSeriesContentByID(auditor *audit.Auditor, r *http.Request, id strin
|
||||
return series_content, err
|
||||
}
|
||||
|
||||
var mangas struct {
|
||||
// Define a temporary struct to match the expected JSON response from the API
|
||||
var manga struct {
|
||||
Thumbnails struct {
|
||||
List []ArtworkBrief `json:"illust"`
|
||||
List []ArtworkBrief `json:"illust"` // List of thumbnail images for artworks
|
||||
} `json:"thumbnails"`
|
||||
IllustSeries []MangaSeries `json:"illustSeries"`
|
||||
Page MangaSeriesContent `json:"page"`
|
||||
IllustSeries []MangaSeries `json:"illustSeries"` // List of illustration series metadata
|
||||
Page MangaSeriesContent `json:"page"` // Page-specific content and metadata
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(resp), &mangas)
|
||||
// Unmarshal the JSON response into the temporary "manga" struct
|
||||
err = json.Unmarshal([]byte(resp), &manga)
|
||||
if err != nil {
|
||||
return series_content, err
|
||||
}
|
||||
|
||||
series_content = mangas.Page
|
||||
// Assign the page-specific content to the main series_content variable
|
||||
series_content = manga.Page
|
||||
|
||||
// Iterate over each series entry to populate the Brief field with corresponding artwork details
|
||||
for idx, content := range series_content.Series {
|
||||
for _, item := range mangas.Thumbnails.List {
|
||||
for _, item := range manga.Thumbnails.List {
|
||||
if item.ID == content.WorkID {
|
||||
// If a match is found, assign the ArtworkBrief to the current series entry
|
||||
series_content.Series[idx].Brief = item
|
||||
|
||||
// Populate thumbnails
|
||||
err := series_content.Series[idx].Brief.PopulateThumbnails(auditor)
|
||||
if err != nil {
|
||||
return series_content, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
|
||||
// Break the inner loop with the matching artwork having been found and processed
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, brief := range mangas.IllustSeries {
|
||||
// Iterate over IllustSeries to find and assign the Brief metadata for the series
|
||||
for _, brief := range manga.IllustSeries {
|
||||
// Compare the series ID from the API response with the series_content's SeriesID
|
||||
if brief.ID == strconv.Itoa(series_content.SeriesID) {
|
||||
// Assign the matching MangaSeries metadata to the Brief field of series_content
|
||||
series_content.Brief = brief
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"codeberg.org/vnpower/pixivfe/v2/audit"
|
||||
@@ -31,5 +32,14 @@ func GetNewestArtworks(auditor *audit.Auditor, r *http.Request, worktype string,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range body.Artworks {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
body.Artworks[id] = artwork
|
||||
}
|
||||
|
||||
return body.Artworks, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"codeberg.org/vnpower/pixivfe/v2/audit"
|
||||
@@ -40,5 +41,14 @@ func GetNewestFromFollowing(auditor *audit.Auditor, r *http.Request, mode, page
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range artworks.Artworks {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
artworks.Artworks[id] = artwork
|
||||
}
|
||||
|
||||
return artworks.Artworks, nil
|
||||
}
|
||||
|
||||
+30
-20
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -29,30 +30,34 @@ const (
|
||||
)
|
||||
|
||||
type Ranking struct {
|
||||
Contents []struct {
|
||||
Title string `json:"title"`
|
||||
Thumbnail string `json:"url"`
|
||||
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
|
||||
} `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"`
|
||||
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)
|
||||
|
||||
@@ -101,6 +106,11 @@ func GetRanking(auditor *audit.Auditor, r *http.Request, mode, content, date, pa
|
||||
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
|
||||
|
||||
+35
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
@@ -167,6 +168,15 @@ func getPopularSearch(auditor *audit.Auditor, r *http.Request, settings SearchPa
|
||||
// TODO: populate Popular (the regular one) and RelatedTags
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range result.Artworks.Artworks {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
result.Artworks.Artworks[id] = artwork
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -217,6 +227,31 @@ func getStandardSearch(auditor *audit.Auditor, r *http.Request, settings SearchP
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for id, artwork := range artworks.Artworks {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
artworks.Artworks[id] = artwork
|
||||
}
|
||||
|
||||
for id, artwork := range resultRaw.Popular.Permanent {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
resultRaw.Popular.Permanent[id] = artwork
|
||||
}
|
||||
|
||||
for id, artwork := range resultRaw.Popular.Recent {
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
resultRaw.Popular.Recent[id] = artwork
|
||||
}
|
||||
|
||||
// Assign artworks and popular data to the result
|
||||
result.Artworks = artworks
|
||||
result.Popular = resultRaw.Popular
|
||||
|
||||
+111
@@ -1,8 +1,12 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"regexp"
|
||||
|
||||
"codeberg.org/vnpower/pixivfe/v2/audit"
|
||||
)
|
||||
@@ -14,3 +18,110 @@ type RequestContext struct {
|
||||
auditor *audit.Auditor
|
||||
request *http.Request
|
||||
}
|
||||
|
||||
// Thumbnails encapsulates all thumbnail sizes.
|
||||
type Thumbnails struct {
|
||||
Tiny string
|
||||
Small string
|
||||
Medium string
|
||||
Large string
|
||||
Original string
|
||||
}
|
||||
|
||||
func (work *ArtworkBrief) PopulateThumbnails(auditor *audit.Auditor) error {
|
||||
thumbnails, err := PopulateThumbnailsFor(auditor, work.Thumbnail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
work.Thumbnails = thumbnails
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Ranking) PopulateThumbnails(auditor *audit.Auditor) error {
|
||||
for i := range r.Contents {
|
||||
err := r.Contents[i].PopulateThumbnails(auditor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (content *RankingContent) PopulateThumbnails(auditor *audit.Auditor) error {
|
||||
thumbnails, err := PopulateThumbnailsFor(auditor, content.Thumbnail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.Thumbnails = thumbnails
|
||||
return nil
|
||||
}
|
||||
|
||||
// PopulateThumbnailsFor is a helper function
|
||||
func PopulateThumbnailsFor(auditor *audit.Auditor, thumbnailURL string) (Thumbnails, error) {
|
||||
var thumbnails Thumbnails
|
||||
|
||||
// auditor.SugaredLogger.Debugf("PopulateThumbnails called with Thumbnail URL: %s", thumbnailURL)
|
||||
|
||||
// Parse the original Thumbnail URL to ensure it's valid
|
||||
parsedURL, err := url.Parse(thumbnailURL)
|
||||
if err != nil {
|
||||
auditor.SugaredLogger.Errorf("Invalid Thumbnail URL '%s': %v", thumbnailURL, err)
|
||||
return thumbnails, fmt.Errorf("invalid Thumbnail URL: %w", err)
|
||||
}
|
||||
|
||||
// Define a regex to match the "/c/{parameters}/" segment
|
||||
re := regexp.MustCompile(`/c/[^/]+/`)
|
||||
|
||||
// Verify that the Thumbnail URL contains the expected pattern
|
||||
if !re.MatchString(parsedURL.Path) {
|
||||
auditor.SugaredLogger.Errorf("Thumbnail URL does not match expected pattern: %s", thumbnailURL)
|
||||
return thumbnails, fmt.Errorf("Thumbnail URL does not match expected pattern")
|
||||
}
|
||||
|
||||
// Define the desired sizes for the thumbnails along with corresponding fields
|
||||
thumbSizes := []struct {
|
||||
name string
|
||||
size string
|
||||
field *string
|
||||
}{
|
||||
{"Tiny", "250x250", &thumbnails.Tiny},
|
||||
{"Small", "360x360", &thumbnails.Small},
|
||||
{"Medium", "540x540", &thumbnails.Medium},
|
||||
{"Large", "1200x1200", &thumbnails.Large},
|
||||
}
|
||||
|
||||
// Iterate over each size and generate the corresponding URL
|
||||
for _, thumb := range thumbSizes {
|
||||
finalURL := generateThumbnailURL(parsedURL, re, thumb.size)
|
||||
*thumb.field = finalURL
|
||||
// auditor.SugaredLogger.Debugf("Set Thumbnails.%s to: %s", thumb.name, finalURL)
|
||||
}
|
||||
|
||||
// Construct the Original URL by removing the "/c/{size}_{quality}/" segment
|
||||
finalOriginalURL := generateOriginalURL(parsedURL, re)
|
||||
thumbnails.Original = finalOriginalURL
|
||||
|
||||
// auditor.SugaredLogger.Debugf("Set Thumbnails.Original to: %s", finalOriginalURL)
|
||||
|
||||
return thumbnails, nil
|
||||
}
|
||||
|
||||
// generateThumbnailURL constructs a thumbnail URL for a given size.
|
||||
func generateThumbnailURL(parsedURL *url.URL, re *regexp.Regexp, size string) string {
|
||||
// Replace the existing size and quality segment with the new size
|
||||
newPath := re.ReplaceAllString(parsedURL.Path, fmt.Sprintf("/c/%s/", size))
|
||||
updatedURL := *parsedURL // Copy
|
||||
updatedURL.Path = newPath
|
||||
return updatedURL.String()
|
||||
}
|
||||
|
||||
// generateOriginalURL constructs the original image URL by removing the size and quality segment.
|
||||
func generateOriginalURL(parsedURL *url.URL, re *regexp.Regexp) string {
|
||||
// Remove the size and quality segment
|
||||
originalPath := re.ReplaceAllString(parsedURL.Path, "/")
|
||||
// Clean up the path to ensure it's correctly formatted
|
||||
originalPath = path.Clean(originalPath)
|
||||
originalURL := *parsedURL
|
||||
originalURL.Path = originalPath
|
||||
return originalURL.String()
|
||||
}
|
||||
|
||||
+43
-24
@@ -199,7 +199,7 @@ func getPopulatedWorks(auditor *audit.Auditor, r *http.Request, user *User, id s
|
||||
switch cat.Value {
|
||||
case "illustrations", "manga":
|
||||
auditor.Logger.Debug("Fetching and populating ArtworkBriefs", zap.String("category", cat.Value))
|
||||
artworks, err := fetchPopulatedBriefs[ArtworkBrief](auditor, r, id, cat.WorkIDs, fetchArtworkIDs)
|
||||
artworks, err := fetchPopulatedArtworkBriefs(auditor, r, id, cat.WorkIDs, fetchArtworkIDs)
|
||||
if err != nil {
|
||||
auditor.SugaredLogger.Error("Failed to fetch populated ArtworkBriefs", zap.Error(err))
|
||||
return err
|
||||
@@ -208,7 +208,7 @@ func getPopulatedWorks(auditor *audit.Auditor, r *http.Request, user *User, id s
|
||||
|
||||
case "novels":
|
||||
auditor.Logger.Debug("Fetching and populating NovelBriefs", zap.String("category", cat.Value))
|
||||
novels, err := fetchPopulatedBriefs[NovelBrief](auditor, r, id, cat.WorkIDs, fetchNovelIDs)
|
||||
novels, err := fetchPopulatedNovelBriefs(auditor, r, id, cat.WorkIDs, fetchNovelIDs)
|
||||
if err != nil {
|
||||
auditor.SugaredLogger.Error("Failed to fetch populated NovelBriefs", zap.Error(err))
|
||||
return err
|
||||
@@ -407,37 +407,50 @@ func extractIDs(rawMessage *json.RawMessage, categoryName string) ([]int, int, e
|
||||
return ids, len(dataMap), nil
|
||||
}
|
||||
|
||||
// The HasID interface allows for generic handling of the ArtworkBrief
|
||||
// and NovelBrief structs, which both contain an ID string.
|
||||
type HasID interface {
|
||||
GetID() string
|
||||
}
|
||||
|
||||
// GetID implements the HasID interface for the ArtworkBrief struct.
|
||||
func (a ArtworkBrief) GetID() string {
|
||||
return a.ID
|
||||
}
|
||||
|
||||
// GetID implements the HasID interface for the NovelBrief struct.
|
||||
func (n NovelBrief) GetID() string {
|
||||
return n.ID
|
||||
}
|
||||
|
||||
// fetchPopulatedBriefs is a generic function that fetches and processes items of type T,
|
||||
// where T must implement the HasID interface.
|
||||
func fetchPopulatedBriefs[T HasID](
|
||||
// fetchPopulatedArtworkBriefs fetches and processes ArtworkBrief items.
|
||||
func fetchPopulatedArtworkBriefs(
|
||||
auditor *audit.Auditor,
|
||||
r *http.Request,
|
||||
id, ids string,
|
||||
fetchFunc func(*audit.Auditor, *http.Request, string, string) ([]T, error),
|
||||
) ([]T, error) {
|
||||
fetchFunc func(*audit.Auditor, *http.Request, string, string) ([]ArtworkBrief, error),
|
||||
) ([]ArtworkBrief, error) {
|
||||
items, err := fetchFunc(auditor, r, id, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sort the items based on ID in descending order
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return numberGreaterThan(items[i].GetID(), items[j].GetID())
|
||||
return numberGreaterThan(items[i].ID, items[j].ID)
|
||||
})
|
||||
|
||||
// Populate thumbnails for each artwork
|
||||
for idx := range items {
|
||||
artwork := &items[idx]
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", artwork.ID, err)
|
||||
return nil, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", artwork.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// fetchPopulatedNovelBriefs fetches and processes NovelBrief items.
|
||||
func fetchPopulatedNovelBriefs(
|
||||
auditor *audit.Auditor,
|
||||
r *http.Request,
|
||||
id, ids string,
|
||||
fetchFunc func(*audit.Auditor, *http.Request, string, string) ([]NovelBrief, error),
|
||||
) ([]NovelBrief, error) {
|
||||
items, err := fetchFunc(auditor, r, id, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Sort the items based on ID in descending order
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return numberGreaterThan(items[i].ID, items[j].ID)
|
||||
})
|
||||
|
||||
return items, nil
|
||||
@@ -585,6 +598,12 @@ func fetchBookmarks(auditor *audit.Auditor, r *http.Request, id, mode string, pa
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Populate thumbnails
|
||||
if err := artwork.PopulateThumbnails(auditor); err != nil {
|
||||
auditor.SugaredLogger.Errorf("Failed to populate thumbnails for artwork ID %s: %v", id, err)
|
||||
return nil, -1, fmt.Errorf("failed to populate thumbnails for artwork ID %s: %w", id, err)
|
||||
}
|
||||
artworks[index] = artwork
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user