User page

This commit is contained in:
VnPower
2024-01-20 11:41:28 +07:00
parent 6e87d4ae80
commit dc1698e8ab
4 changed files with 351 additions and 0 deletions
+30
View File
@@ -28,3 +28,33 @@ func GetRankingCalendarURL(mode string, year, month int) string {
return fmt.Sprintf(base, mode, year, month)
}
func GetUserInformationURL(id string) string {
base := "https://www.pixiv.net/ajax/user/%s?full=1"
return fmt.Sprintf(base, id)
}
func GetUserArtworksURL(id string) string {
base := "https://www.pixiv.net/ajax/user/%s/profile/all"
return fmt.Sprintf(base, id)
}
func GetUserFullArtworkURL(id, ids string) string {
base := "https://www.pixiv.net/ajax/user/%s/profile/illusts?work_category=illustManga&is_first_page=0&lang=en%s"
return fmt.Sprintf(base, id, ids)
}
func GetUserBookmarksURL(id, mode string, page int) string {
base := "https://www.pixiv.net/ajax/user/%s/illusts/bookmarks?tag=&offset=%d&limit=48&rest=%s"
return fmt.Sprintf(base, id, page*48, mode)
}
func GetFrequentTagsURL(ids string) string {
base := "https://www.pixiv.net/ajax/tags/frequent/illust?%s"
return fmt.Sprintf(base, ids)
}
+284
View File
@@ -0,0 +1,284 @@
package core
import (
"errors"
"fmt"
"html/template"
"math"
"sort"
"strconv"
session "codeberg.org/vnpower/pixivfe/v2/core/config"
http "codeberg.org/vnpower/pixivfe/v2/core/http"
"github.com/goccy/go-json"
"github.com/gofiber/fiber/v2"
)
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"`
BackgroundImage string `json:"background"`
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"`
ArtworksCount int
FrequentTags []FrequentTag
Social map[string]map[string]string
Background map[string]interface{} `json:"background"`
}
func (s *User) ParseSocial() {
if string(s.SocialRaw[:]) == "[]" {
// Fuck Pixiv
return
}
_ = json.Unmarshal(s.SocialRaw, &s.Social)
}
func GetFrequentTags(ids string) ([]FrequentTag, error) {
var tags []FrequentTag
URL := http.GetFrequentTagsURL(ids)
response, err := http.UnwrapWebAPIRequest(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
imageProxy := session.GetImageProxy(c)
URL := http.GetUserFullArtworkURL(id, ids)
resp, err := http.UnwrapWebAPIRequest(URL, "")
if err != nil {
return nil, err
}
resp = ProxyImages(resp, imageProxy)
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 GetUserArtworksID(id, category string, page int) (string, int, error) {
URL := http.GetUserArtworksURL(id)
resp, err := http.UnwrapWebAPIRequest(URL, "")
if err != nil {
return "", -1, err
}
var body struct {
Illusts json.RawMessage `json:"illusts"`
Mangas json.RawMessage `json:"manga"`
}
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
count := 0
if err = json.Unmarshal(body.Illusts, &illusts); err != nil {
illusts = make(map[int]string)
}
if err = json.Unmarshal(body.Mangas, &mangas); err != nil {
mangas = make(map[int]string)
}
// Get the keys, because Pixiv only returns IDs (very evil)
if category == "illustrations" || category == "artworks" {
for k := range illusts {
ids = append(ids, k)
count++
}
}
if category == "manga" || category == "artworks" {
for k := range mangas {
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("Page overflow")
}
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)
}
if count == 0 {
// No artworks
return "", -1, errors.New("No artworks found for the current filter.")
}
return idsString, count, nil
}
func GetUserArtwork(c *fiber.Ctx, id, category string, page int) (User, error) {
var user User
imageProxy := session.GetImageProxy(c)
token := session.GetToken(c)
URL := http.GetUserInformationURL(id)
resp, err := http.UnwrapWebAPIRequest(URL, token)
if err != nil {
return user, err
}
resp = ProxyImages(resp, imageProxy)
err = json.Unmarshal([]byte(resp), &user)
if err != nil {
return user, err
}
if category != "bookmarks" {
ids, count, err := GetUserArtworksID(id, category, page)
if err != nil {
return user, err
}
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, _ := strconv.Atoi(works[i].ID)
right, _ := strconv.Atoi(works[j].ID)
return left > right
})
user.Artworks = works
// Artworks count
user.ArtworksCount = count
user.FrequentTags, err = GetFrequentTags(ids)
if err != nil {
return user, err
}
} else {
// Bookmarks
works, count, err := GetUserBookmarks(c, id, "show", page)
if err != nil {
return user, err
}
user.Artworks = works
// Public bookmarks count
user.ArtworksCount = count
}
user.ParseSocial()
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--
imageProxy := session.GetImageProxy(c)
URL := http.GetUserBookmarksURL(id, mode, page)
resp, err := http.UnwrapWebAPIRequest(URL, "")
if err != nil {
return nil, -1, err
}
resp = ProxyImages(resp, imageProxy)
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
}
+1
View File
@@ -111,6 +111,7 @@ func main() {
server.Get("discovery", pages.DiscoveryPage)
server.Get("ranking", pages.RankingPage)
server.Get("rankingCalendar", pages.RankingCalendarPage)
server.Get("users/:id/:category?", pages.UserPage)
// Settings group
server.Get("login", pages.LoginPage)
+36
View File
@@ -0,0 +1,36 @@
package pages
import (
"errors"
"math"
"strconv"
core "codeberg.org/vnpower/pixivfe/v2/core/webapi"
"github.com/gofiber/fiber/v2"
)
func UserPage(c *fiber.Ctx) error {
id := c.Params("id")
if _, err := strconv.Atoi(id); err != nil {
return err
}
category := c.Params("category", "artworks")
if !(category == "artworks" || category == "illustrations" || category == "manga" || category == "bookmarks") {
return errors.New("Invalid work category: only illustrations, manga, artworks and bookmarks are available")
}
page := c.Query("page", "1")
pageInt, _ := strconv.Atoi(page)
user, err := core.GetUserArtwork(c, id, category, pageInt)
if err != nil {
return err
}
var worksCount int
worksCount = user.ArtworksCount
pageLimit := math.Ceil(float64(worksCount) / 30.0)
return c.Render("pages/user", fiber.Map{"Title": user.Name, "User": user, "Category": category, "PageLimit": int(pageLimit), "Page": pageInt})
}