mirror of
https://codeberg.org/VnPower/PixivFE
synced 2024-12-06 19:16:23 +01:00
408 lines
9.2 KiB
Go
408 lines
9.2 KiB
Go
package core
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"html/template"
|
|
"math"
|
|
"sort"
|
|
|
|
http "codeberg.org/vnpower/pixivfe/v2/core/http"
|
|
session "codeberg.org/vnpower/pixivfe/v2/core/session"
|
|
"github.com/goccy/go-json"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// pixivfe internal data type. not used by pixiv.
|
|
type UserArtCategory string
|
|
|
|
const (
|
|
UserArt_Any UserArtCategory = ""
|
|
UserArt_AnyAlt UserArtCategory = "artworks"
|
|
UserArt_Illustration UserArtCategory = "illustrations"
|
|
UserArt_Manga UserArtCategory = "manga"
|
|
UserArt_Bookmarked UserArtCategory = "bookmarks" // what this user has bookmarked; not art by this user
|
|
UserArt_Novel UserArtCategory = "novels"
|
|
)
|
|
|
|
func (s UserArtCategory) Validate() error {
|
|
if s != UserArt_Any &&
|
|
s != UserArt_AnyAlt &&
|
|
s != UserArt_Illustration &&
|
|
s != UserArt_Manga &&
|
|
s != UserArt_Bookmarked &&
|
|
s != UserArt_Novel {
|
|
return fmt.Errorf("Invalid work category: %#v. "+`Only "%s", "%s", "%s", "%s", "%s" and "%s" are available`, s, UserArt_Any, UserArt_AnyAlt, UserArt_Illustration, UserArt_Manga, UserArt_Bookmarked, UserArt_Novel)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type FrequentTag struct {
|
|
Name string `json:"tag"`
|
|
TranslatedName string `json:"tag_translation"`
|
|
}
|
|
|
|
type User struct {
|
|
ID string `json:"userId"`
|
|
Name string `json:"name"`
|
|
Avatar string `json:"imageBig"`
|
|
Following int `json:"following"`
|
|
MyPixiv int `json:"mypixivCount"`
|
|
Comment template.HTML `json:"commentHtml"`
|
|
Webpage string `json:"webpage"`
|
|
SocialRaw json.RawMessage `json:"social"`
|
|
Artworks []ArtworkBrief `json:"artworks"`
|
|
Novels []NovelBrief `json:"novels"`
|
|
Background map[string]interface{} `json:"background"`
|
|
ArtworksCount int
|
|
FrequentTags []FrequentTag
|
|
Social map[string]map[string]string
|
|
BackgroundImage string
|
|
}
|
|
|
|
func (s *User) ParseSocial() error {
|
|
if string(s.SocialRaw[:]) == "[]" {
|
|
// Fuck Pixiv
|
|
return nil
|
|
}
|
|
|
|
err := json.Unmarshal(s.SocialRaw, &s.Social)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetFrequentTags(c *fiber.Ctx, ids string, category UserArtCategory) ([]FrequentTag, error) {
|
|
var tags []FrequentTag
|
|
var URL string
|
|
|
|
if category != "novels" {
|
|
URL = http.GetFrequentArtworkTagsURL(ids)
|
|
} else {
|
|
URL = http.GetFrequentNovelTagsURL(ids)
|
|
}
|
|
|
|
response, err := http.UnwrapWebAPIRequest(c.Context(), URL, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(response), &tags)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return tags, nil
|
|
}
|
|
|
|
func GetUserArtworks(c *fiber.Ctx, id, ids string) ([]ArtworkBrief, error) {
|
|
var works []ArtworkBrief
|
|
|
|
URL := http.GetUserFullArtworkURL(id, ids)
|
|
|
|
resp, err := http.UnwrapWebAPIRequest(c.Context(), URL, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp = session.ProxyImageUrl(c, resp)
|
|
|
|
var body struct {
|
|
Illusts map[int]json.RawMessage `json:"works"`
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(resp), &body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, v := range body.Illusts {
|
|
var illust ArtworkBrief
|
|
err = json.Unmarshal(v, &illust)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
works = append(works, illust)
|
|
}
|
|
|
|
return works, nil
|
|
}
|
|
|
|
func GetUserNovels(c *fiber.Ctx, id, ids string) ([]NovelBrief, error) {
|
|
// VnPower: we can merge this function into GetUserArtworks, but I want to make things simple for now
|
|
var works []NovelBrief
|
|
|
|
URL := http.GetUserFullNovelURL(id, ids)
|
|
|
|
resp, err := http.UnwrapWebAPIRequest(c.Context(), URL, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp = session.ProxyImageUrl(c, resp)
|
|
|
|
var body struct {
|
|
Novels map[int]json.RawMessage `json:"works"`
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(resp), &body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, v := range body.Novels {
|
|
var novel NovelBrief
|
|
err = json.Unmarshal(v, &novel)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
works = append(works, novel)
|
|
}
|
|
|
|
return works, nil
|
|
}
|
|
|
|
func GetUserArtworksID(c *fiber.Ctx, id string, category UserArtCategory, page int) (string, int, error) {
|
|
URL := http.GetUserArtworksURL(id)
|
|
|
|
resp, err := http.UnwrapWebAPIRequest(c.Context(), URL, "")
|
|
if err != nil {
|
|
return "", -1, err
|
|
}
|
|
|
|
var body struct {
|
|
Illusts json.RawMessage `json:"illusts"`
|
|
Mangas json.RawMessage `json:"manga"`
|
|
Novels json.RawMessage `json:"novels"`
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(resp), &body)
|
|
if err != nil {
|
|
return "", -1, err
|
|
}
|
|
|
|
var ids []int
|
|
var idsString string
|
|
|
|
err = json.Unmarshal([]byte(resp), &body)
|
|
if err != nil {
|
|
return "", -1, err
|
|
}
|
|
|
|
var illusts map[int]string
|
|
var mangas map[int]string
|
|
var novels map[int]string
|
|
count := 0
|
|
|
|
// Get the keys, because Pixiv only returns IDs (very evil)
|
|
|
|
if category == UserArt_Illustration || category == UserArt_Any || category == UserArt_AnyAlt {
|
|
if err = json.Unmarshal(body.Illusts, &illusts); err != nil {
|
|
illusts = make(map[int]string)
|
|
}
|
|
for k := range illusts {
|
|
ids = append(ids, k)
|
|
count++
|
|
}
|
|
}
|
|
if category == UserArt_Manga || category == UserArt_Any {
|
|
if err = json.Unmarshal(body.Mangas, &mangas); err != nil {
|
|
mangas = make(map[int]string)
|
|
}
|
|
for k := range mangas {
|
|
ids = append(ids, k)
|
|
count++
|
|
}
|
|
}
|
|
if category == UserArt_Novel {
|
|
if err = json.Unmarshal(body.Novels, &novels); err != nil {
|
|
novels = make(map[int]string)
|
|
}
|
|
for k := range novels {
|
|
ids = append(ids, k)
|
|
count++
|
|
}
|
|
|
|
}
|
|
|
|
// Reverse sort the ids
|
|
sort.Sort(sort.Reverse(sort.IntSlice(ids)))
|
|
|
|
worksNumber := float64(count)
|
|
worksPerPage := 30.0
|
|
|
|
if page < 1 || float64(page) > math.Ceil(worksNumber/worksPerPage)+1.0 {
|
|
return "", -1, errors.New("No page available.")
|
|
}
|
|
|
|
start := (page - 1) * int(worksPerPage)
|
|
end := int(min(float64(page)*worksPerPage, worksNumber)) // no overflow
|
|
|
|
for _, k := range ids[start:end] {
|
|
idsString += fmt.Sprintf("&ids[]=%d", k)
|
|
}
|
|
|
|
return idsString, count, nil
|
|
}
|
|
|
|
func GetUserArtwork(c *fiber.Ctx, id string, category UserArtCategory, page int, getTags bool) (User, error) {
|
|
var user User
|
|
|
|
token := session.GetPixivToken(c)
|
|
|
|
URL := http.GetUserInformationURL(id)
|
|
|
|
resp, err := http.UnwrapWebAPIRequest(c.Context(), URL, token)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
resp = session.ProxyImageUrl(c, resp)
|
|
|
|
err = json.Unmarshal([]byte(resp), &user)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
if category == "bookmarks" {
|
|
// Bookmarks
|
|
works, count, err := GetUserBookmarks(c, id, "show", page)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
user.Artworks = works
|
|
|
|
// Public bookmarks count
|
|
user.ArtworksCount = count
|
|
} else if category == "novels" {
|
|
ids, count, err := GetUserArtworksID(c, id, category, page)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
if count > 0 {
|
|
// Check if the user has artworks available or not
|
|
works, err := GetUserNovels(c, id, ids)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
// IDK but the order got shuffled even though Pixiv sorted the IDs in the response
|
|
sort.Slice(works[:], func(i, j int) bool {
|
|
left := works[i].ID
|
|
right := works[j].ID
|
|
return numberGreaterThan(left, right)
|
|
})
|
|
user.Novels = works
|
|
|
|
if getTags {
|
|
user.FrequentTags, err = GetFrequentTags(c, ids, category)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
}
|
|
}
|
|
|
|
// Artworks count
|
|
user.ArtworksCount = count
|
|
} else {
|
|
ids, count, err := GetUserArtworksID(c, id, category, page)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
if count > 0 {
|
|
// Check if the user has artworks available or not
|
|
works, err := GetUserArtworks(c, id, ids)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
// IDK but the order got shuffled even though Pixiv sorted the IDs in the response
|
|
sort.Slice(works[:], func(i, j int) bool {
|
|
left := works[i].ID
|
|
right := works[j].ID
|
|
return numberGreaterThan(left, right)
|
|
})
|
|
user.Artworks = works
|
|
|
|
if getTags {
|
|
user.FrequentTags, err = GetFrequentTags(c, ids, category)
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
}
|
|
}
|
|
|
|
// Artworks count
|
|
user.ArtworksCount = count
|
|
}
|
|
|
|
err = user.ParseSocial()
|
|
if err != nil {
|
|
return User{}, err
|
|
}
|
|
|
|
if user.Background != nil {
|
|
user.BackgroundImage = user.Background["url"].(string)
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func GetUserBookmarks(c *fiber.Ctx, id, mode string, page int) ([]ArtworkBrief, int, error) {
|
|
page--
|
|
|
|
URL := http.GetUserBookmarksURL(id, mode, page)
|
|
|
|
resp, err := http.UnwrapWebAPIRequest(c.Context(), URL, "")
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
resp = session.ProxyImageUrl(c, resp)
|
|
|
|
var body struct {
|
|
Artworks []json.RawMessage `json:"works"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
err = json.Unmarshal([]byte(resp), &body)
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
|
|
artworks := make([]ArtworkBrief, len(body.Artworks))
|
|
|
|
for index, value := range body.Artworks {
|
|
var artwork ArtworkBrief
|
|
|
|
err = json.Unmarshal([]byte(value), &artwork)
|
|
if err != nil {
|
|
artworks[index] = ArtworkBrief{
|
|
ID: "#",
|
|
Title: "Deleted or Private",
|
|
Thumbnail: "https://s.pximg.net/common/images/limit_unknown_360.png",
|
|
}
|
|
continue
|
|
}
|
|
artworks[index] = artwork
|
|
}
|
|
|
|
return artworks, body.Total, nil
|
|
}
|
|
|
|
func numberGreaterThan(l, r string) bool {
|
|
if len(l) > len(r) {
|
|
return true
|
|
}
|
|
if len(l) < len(r) {
|
|
return false
|
|
}
|
|
return l > r
|
|
}
|