mirror of
https://codeberg.org/VnPower/PixivFE
synced 2024-12-06 19:16:23 +01:00
User page
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
Reference in New Issue
Block a user