mirror of
https://codeberg.org/VnPower/PixivFE
synced 2024-12-06 19:16:23 +01:00
try refactoring core/user again
This commit is contained in:
+208
-111
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"codeberg.org/vnpower/pixivfe/v2/i18n"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/session"
|
||||
@@ -24,6 +25,13 @@ const (
|
||||
CategoryNovels UserWorkCategory = "novels"
|
||||
)
|
||||
|
||||
// UserWorkIDs holds separate ID strings for illustrations, manga, and novels.
|
||||
type UserWorkIDs struct {
|
||||
IllustrationIDs string
|
||||
MangaIDs string
|
||||
NovelIDs string
|
||||
}
|
||||
|
||||
func (s UserWorkCategory) Validate() error {
|
||||
if s != CategoryAny &&
|
||||
s != CategoryAnyAlt &&
|
||||
@@ -155,44 +163,134 @@ func fetchUserWorks(r *http.Request, user *User, id string, category UserWorkCat
|
||||
}
|
||||
|
||||
user.Artworks = works
|
||||
user.NovelSeries = nil
|
||||
user.MangaSeries = nil
|
||||
user.CategoryItemCount = count
|
||||
} else {
|
||||
// Fetch artworks or novels
|
||||
ids, countInfo, series, err := getUserArtworksIDAndSeries(r, id, category, page)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fetch artworks or novels
|
||||
userWorkIDs, countInfo, series, err := getUserArtworksIDAndSeries(r, id, category, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize ID strings for different work types
|
||||
var illustrationIDs, mangaIDs, novelIDs string
|
||||
|
||||
switch category {
|
||||
case CategoryIllustration:
|
||||
illustrationIDs = userWorkIDs.IllustrationIDs
|
||||
case CategoryManga:
|
||||
mangaIDs = userWorkIDs.MangaIDs
|
||||
case CategoryNovels:
|
||||
novelIDs = userWorkIDs.NovelIDs
|
||||
case CategoryAny, CategoryAnyAlt:
|
||||
// Combine all relevant ID strings
|
||||
illustrationIDs = userWorkIDs.IllustrationIDs
|
||||
mangaIDs = userWorkIDs.MangaIDs
|
||||
novelIDs = userWorkIDs.NovelIDs
|
||||
default:
|
||||
return fmt.Errorf("unsupported category: %v", category)
|
||||
}
|
||||
|
||||
// Flags to determine which work types to fetch
|
||||
fetchArtworks := false
|
||||
fetchNovels := false
|
||||
|
||||
switch category {
|
||||
case CategoryIllustration, CategoryManga, CategoryAny, CategoryAnyAlt:
|
||||
fetchArtworks = true
|
||||
case CategoryNovels:
|
||||
fetchNovels = true
|
||||
}
|
||||
|
||||
// Early return if there are no works to fetch
|
||||
if countInfo.All == 0 {
|
||||
user.Artworks = nil
|
||||
user.CategoryItemCount = 0
|
||||
user.NovelSeries = nil
|
||||
user.MangaSeries = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fetch and process novels if required
|
||||
if fetchNovels && novelIDs != "" {
|
||||
ids := novelIDs
|
||||
novels, err := fetchAndProcessItems[NovelBrief](r, id, ids, getUserNovelIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.Novels = novels
|
||||
}
|
||||
|
||||
// Fetch and process artworks if required
|
||||
if fetchArtworks && (illustrationIDs != "" || mangaIDs != "") {
|
||||
// Combine Illustration and Manga IDs
|
||||
ids := illustrationIDs + mangaIDs
|
||||
artworks, err := fetchAndProcessItems[ArtworkBrief](r, id, ids, getUserArtworkIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if countInfo.All > 0 {
|
||||
artworks, novels, err := fetchAndProcessArtworks(r, id, ids, category)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if category == CategoryNovels {
|
||||
user.Novels = novels
|
||||
} else {
|
||||
user.Artworks = artworks
|
||||
user.Illustrations = filterArtworksByType(artworks, 0)
|
||||
user.Manga = filterArtworksByType(artworks, 1)
|
||||
}
|
||||
|
||||
if getTags {
|
||||
user.FrequentTags, err = getUserFrequentTags(r, ids, category)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle series data
|
||||
user.NovelSeries, user.MangaSeries = handleSeriesData(series, category)
|
||||
user.CategoryItemCount = countInfo.All
|
||||
user.Artworks = artworks
|
||||
user.Illustrations = filterArtworksByType(artworks, 0)
|
||||
user.Manga = filterArtworksByType(artworks, 1)
|
||||
}
|
||||
|
||||
// Fetch frequent tags if requested
|
||||
if getTags {
|
||||
// Combine all IDs when fetching tags for 'Any' categories
|
||||
tagsIDs := illustrationIDs + mangaIDs + novelIDs
|
||||
|
||||
user.FrequentTags, err = getUserFrequentTags(r, tagsIDs, category)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Handle series data
|
||||
user.NovelSeries, user.MangaSeries = handleSeriesData(series, category)
|
||||
user.CategoryItemCount = countInfo.All
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The HasID interface allows for generic handling of the ArtworkBrief
|
||||
// and NovelBrief struct structs, which both contaisn an ID string.
|
||||
type HasID interface {
|
||||
GetID() string
|
||||
}
|
||||
|
||||
// GetID implements the Identifiable interface for the ArtworkBrief struct.
|
||||
func (a ArtworkBrief) GetID() string {
|
||||
return a.ID
|
||||
}
|
||||
|
||||
// GetID implements the Identifiable interface for the NovelBrief struct.
|
||||
func (n NovelBrief) GetID() string {
|
||||
return n.ID
|
||||
}
|
||||
|
||||
// fetchAndProcessItems is a generic function that fetches and processes items of type T,
|
||||
// where T must implement the HasID interface.
|
||||
func fetchAndProcessItems[T HasID](
|
||||
r *http.Request,
|
||||
id, ids string,
|
||||
fetchFunc func(*http.Request, string, string) ([]T, error),
|
||||
) ([]T, error) {
|
||||
items, err := fetchFunc(r, id, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return numberGreaterThan(items[i].GetID(), items[j].GetID())
|
||||
})
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// filterArtworksByType filters artworks based on the IllustType.
|
||||
func filterArtworksByType(artworks []ArtworkBrief, illustType int) []ArtworkBrief {
|
||||
filtered := make([]ArtworkBrief, 0)
|
||||
@@ -210,8 +308,8 @@ func filterArtworksByType(artworks []ArtworkBrief, illustType int) []ArtworkBrie
|
||||
// don't exist for a user.
|
||||
type IntStringMap map[int]string
|
||||
|
||||
// unmarshalJSON implements custom unmarshalling for IntStringMap.
|
||||
func (m *IntStringMap) unmarshalJSON(data []byte) error {
|
||||
// UnmarshalJSON implements custom unmarshalling for IntStringMap.
|
||||
func (m *IntStringMap) UnmarshalJSON(data []byte) error {
|
||||
// Check if the data is an empty array.
|
||||
if string(data) == "[]" {
|
||||
*m = make(map[int]string)
|
||||
@@ -242,19 +340,18 @@ func (m *IntStringMap) unmarshalJSON(data []byte) error {
|
||||
}
|
||||
|
||||
// getUserArtworksIDAndSeries retrieves artwork IDs and series information for a user.
|
||||
func getUserArtworksIDAndSeries(r *http.Request, id string, category UserWorkCategory, page int) (idsString string, countInfo CountInfo, series json.RawMessage, err error) {
|
||||
// It now returns separate ID strings for illustrations, manga, and novels encapsulated in UserWorkIDs.
|
||||
func getUserArtworksIDAndSeries(r *http.Request, id string, category UserWorkCategory, page int) (userWorkIDs UserWorkIDs, countInfo CountInfo, series json.RawMessage, err error) {
|
||||
URL := GetUserArtworksURL(id)
|
||||
|
||||
resp, err := API_GET_UnwrapJson(r.Context(), URL, "", r.Header)
|
||||
if err != nil {
|
||||
return "", CountInfo{}, nil, err
|
||||
return UserWorkIDs{}, CountInfo{}, nil, err
|
||||
}
|
||||
|
||||
resp = session.ProxyImageUrl(r, resp)
|
||||
|
||||
var body struct {
|
||||
// *json.RawMessage allows us to easily check whether
|
||||
// a field exists by verifying if pointer != nil
|
||||
Illusts *json.RawMessage `json:"illusts"`
|
||||
Manga *json.RawMessage `json:"manga"`
|
||||
MangaSeries *json.RawMessage `json:"mangaSeries"`
|
||||
@@ -264,108 +361,108 @@ func getUserArtworksIDAndSeries(r *http.Request, id string, category UserWorkCat
|
||||
|
||||
err = json.Unmarshal([]byte(resp), &body)
|
||||
if err != nil {
|
||||
return "", CountInfo{}, nil, fmt.Errorf("failed to unmarshal response body: %w", err)
|
||||
return UserWorkIDs{}, CountInfo{}, nil, fmt.Errorf("failed to unmarshal response body: %w", err)
|
||||
}
|
||||
|
||||
var ids []int
|
||||
countInfo = CountInfo{}
|
||||
|
||||
var illusts IntStringMap
|
||||
var manga IntStringMap
|
||||
var novels IntStringMap
|
||||
|
||||
if category == CategoryIllustration || category == CategoryAny || category == CategoryAnyAlt {
|
||||
if body.Illusts != nil && len(*body.Illusts) > 0 {
|
||||
if err = json.Unmarshal(*body.Illusts, &illusts); err != nil {
|
||||
fmt.Printf("Error unmarshalling illusts: %v\n", err)
|
||||
illusts = make(IntStringMap)
|
||||
}
|
||||
for k := range illusts {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
countInfo.All += len(illusts)
|
||||
countInfo.Illustrations = len(illusts)
|
||||
var illustIDs []int
|
||||
var mangaIDs []int
|
||||
var novelIDs []int
|
||||
|
||||
// Process Illustrations
|
||||
if body.Illusts != nil && len(*body.Illusts) > 0 {
|
||||
if err = json.Unmarshal(*body.Illusts, &illusts); err != nil {
|
||||
fmt.Printf("Error unmarshalling illusts: %v\n", err)
|
||||
illusts = make(IntStringMap)
|
||||
}
|
||||
for k := range illusts {
|
||||
illustIDs = append(illustIDs, k)
|
||||
}
|
||||
countInfo.All += len(illusts)
|
||||
countInfo.Illustrations = len(illusts)
|
||||
}
|
||||
|
||||
// Process Manga
|
||||
if body.Manga != nil && len(*body.Manga) > 0 {
|
||||
if err = json.Unmarshal(*body.Manga, &manga); err != nil {
|
||||
fmt.Printf("Error unmarshalling manga: %v\n", err)
|
||||
manga = make(IntStringMap)
|
||||
}
|
||||
for k := range manga {
|
||||
mangaIDs = append(mangaIDs, k)
|
||||
}
|
||||
countInfo.All += len(manga)
|
||||
countInfo.Manga = len(manga)
|
||||
if body.MangaSeries != nil {
|
||||
series = *body.MangaSeries
|
||||
}
|
||||
}
|
||||
|
||||
if category == CategoryManga || category == CategoryAny {
|
||||
if body.Manga != nil && len(*body.Manga) > 0 {
|
||||
if err = json.Unmarshal(*body.Manga, &manga); err != nil {
|
||||
fmt.Printf("Error unmarshalling manga: %v\n", err)
|
||||
manga = make(IntStringMap)
|
||||
}
|
||||
for k := range manga {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
countInfo.All += len(manga)
|
||||
countInfo.Manga = len(manga)
|
||||
if body.MangaSeries != nil {
|
||||
series = *body.MangaSeries
|
||||
}
|
||||
// Process Novels
|
||||
if body.Novels != nil && len(*body.Novels) > 0 {
|
||||
if err = json.Unmarshal(*body.Novels, &novels); err != nil {
|
||||
fmt.Printf("Error unmarshalling novels: %v\n", err)
|
||||
novels = make(IntStringMap)
|
||||
}
|
||||
for k := range novels {
|
||||
novelIDs = append(novelIDs, k)
|
||||
}
|
||||
countInfo.All += len(novels)
|
||||
countInfo.Novels = len(novels)
|
||||
if body.NovelSeries != nil {
|
||||
series = *body.NovelSeries
|
||||
}
|
||||
}
|
||||
|
||||
if category == CategoryNovels {
|
||||
if body.Novels != nil && len(*body.Novels) > 0 {
|
||||
if err = json.Unmarshal(*body.Novels, &novels); err != nil {
|
||||
fmt.Printf("Error unmarshalling novels: %v\n", err)
|
||||
novels = make(IntStringMap)
|
||||
}
|
||||
for k := range novels {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
countInfo.All += len(novels)
|
||||
countInfo.Novels = len(novels)
|
||||
if body.NovelSeries != nil {
|
||||
series = *body.NovelSeries
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(ids)))
|
||||
// Sort IDs in descending order
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(illustIDs)))
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(mangaIDs)))
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(novelIDs)))
|
||||
|
||||
worksPerPage := 30.0
|
||||
|
||||
start, end, err := computeSliceBounds(page, worksPerPage, len(ids))
|
||||
// Compute slice bounds for each category
|
||||
startIllust, endIllust, err := computeSliceBounds(page, worksPerPage, len(illustIDs))
|
||||
if err != nil {
|
||||
return "", CountInfo{}, nil, err
|
||||
}
|
||||
|
||||
// Build the IDs string for the API request
|
||||
for _, k := range ids[start:end] {
|
||||
idsString += fmt.Sprintf("&ids[]=%d", k)
|
||||
}
|
||||
|
||||
return idsString, countInfo, series, nil
|
||||
}
|
||||
|
||||
func fetchAndProcessArtworks(r *http.Request, id, ids string, category UserWorkCategory) ([]ArtworkBrief, []NovelBrief, error) {
|
||||
var artworks []ArtworkBrief
|
||||
var novels []NovelBrief
|
||||
var err error
|
||||
|
||||
if category == CategoryNovels {
|
||||
novels, err = getUserNovelIDs(r, id, ids)
|
||||
} else {
|
||||
artworks, err = getUserArtworkIDs(r, id, ids)
|
||||
return UserWorkIDs{}, CountInfo{}, nil, err
|
||||
}
|
||||
|
||||
startManga, endManga, err := computeSliceBounds(page, worksPerPage, len(mangaIDs))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return UserWorkIDs{}, CountInfo{}, nil, err
|
||||
}
|
||||
|
||||
// Sort the works
|
||||
if category == CategoryNovels {
|
||||
sort.Slice(novels[:], func(i, j int) bool {
|
||||
return numberGreaterThan(novels[i].ID, novels[j].ID)
|
||||
})
|
||||
} else {
|
||||
sort.Slice(artworks[:], func(i, j int) bool {
|
||||
return numberGreaterThan(artworks[i].ID, artworks[j].ID)
|
||||
})
|
||||
startNovel, endNovel, err := computeSliceBounds(page, worksPerPage, len(novelIDs))
|
||||
if err != nil {
|
||||
return UserWorkIDs{}, CountInfo{}, nil, err
|
||||
}
|
||||
|
||||
return artworks, novels, nil
|
||||
// Build the ID strings for each category
|
||||
var idsBuilder strings.Builder
|
||||
|
||||
for _, k := range illustIDs[startIllust:endIllust] {
|
||||
idsBuilder.WriteString(fmt.Sprintf("&ids[]=%d", k))
|
||||
}
|
||||
userWorkIDs.IllustrationIDs = idsBuilder.String()
|
||||
|
||||
idsBuilder.Reset()
|
||||
for _, k := range mangaIDs[startManga:endManga] {
|
||||
idsBuilder.WriteString(fmt.Sprintf("&ids[]=%d", k))
|
||||
}
|
||||
userWorkIDs.MangaIDs = idsBuilder.String()
|
||||
|
||||
idsBuilder.Reset()
|
||||
for _, k := range novelIDs[startNovel:endNovel] {
|
||||
idsBuilder.WriteString(fmt.Sprintf("&ids[]=%d", k))
|
||||
}
|
||||
userWorkIDs.NovelIDs = idsBuilder.String()
|
||||
|
||||
return userWorkIDs, countInfo, series, nil
|
||||
}
|
||||
|
||||
func handleSeriesData(series json.RawMessage, category UserWorkCategory) ([]NovelSeries, []MangaSeries) {
|
||||
|
||||
Reference in New Issue
Block a user