diff --git a/config/proxy_checker.go b/config/proxy_checker.go index f608324..18774f9 100644 --- a/config/proxy_checker.go +++ b/config/proxy_checker.go @@ -21,12 +21,12 @@ var ( stopChan chan struct{} ) -func InitializeProxyChecker(c context.Context) { +func InitializeProxyChecker(r context.Context) { stopChan = make(chan struct{}) - StartProxyChecker(c) + StartProxyChecker(r) } -func StartProxyChecker(c context.Context) { +func StartProxyChecker(r context.Context) { go func() { for { select { @@ -34,7 +34,7 @@ func StartProxyChecker(c context.Context) { log.Println("Stopping proxy checker...") return default: - checkProxies(c) + checkProxies(r) if t := GlobalServerConfig.ProxyCheckInterval; t > 0 { time.Sleep(t) } else { @@ -50,7 +50,7 @@ func StopProxyChecker() { close(stopChan) } -func checkProxies(c context.Context) { +func checkProxies(r context.Context) { logln("Starting proxy check...") var wg sync.WaitGroup var mutex sync.Mutex @@ -62,7 +62,7 @@ func checkProxies(c context.Context) { wg.Add(1) go func(proxyURL string) { defer wg.Done() - isWorking, resp := testProxy(c, proxyURL) + isWorking, resp := testProxy(r, proxyURL) status := "" if resp != nil { status = resp.Status @@ -83,13 +83,13 @@ func checkProxies(c context.Context) { updateWorkingProxies(newWorkingProxies) } -func testProxy(c context.Context, proxyBaseURL string) (bool, *http.Response) { +func testProxy(r context.Context, proxyBaseURL string) (bool, *http.Response) { client := &http.Client{Timeout: proxyCheckTimeout} fullURL := fmt.Sprintf("%s%s", strings.TrimRight(proxyBaseURL, "/"), testImagePath) logf("Testing proxy %s with full URL: %s", proxyBaseURL, fullURL) - req, err := http.NewRequestWithContext(c, "GET", fullURL, nil) + req, err := http.NewRequestWithContext(r, "GET", fullURL, nil) if err != nil { logf("Error creating request for proxy %s: %v", proxyBaseURL, err) return false, nil diff --git a/core/artwork.go b/core/artwork.go index 9ab19de..b9b80f2 100644 --- a/core/artwork.go +++ b/core/artwork.go @@ -131,16 +131,16 @@ type Illust struct { BookmarkID string } -func GetUserBasicInformation(c *http.Request, id string) (UserBrief, error) { +func GetUserBasicInformation(r *http.Request, id string) (UserBrief, error) { var user UserBrief URL := GetUserInformationURL(id) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return user, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) err = json.Unmarshal([]byte(response), &user) if err != nil { @@ -150,17 +150,17 @@ func GetUserBasicInformation(c *http.Request, id string) (UserBrief, error) { return user, nil } -func GetArtworkImages(c *http.Request, id string) ([]Image, error) { +func GetArtworkImages(r *http.Request, id string) ([]Image, error) { var resp []ImageResponse var images []Image URL := GetArtworkImagesURL(id) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) err = json.Unmarshal([]byte(response), &resp) if err != nil { @@ -188,18 +188,18 @@ func GetArtworkImages(c *http.Request, id string) ([]Image, error) { return images, nil } -func GetArtworkComments(c *http.Request, id string) ([]Comment, error) { +func GetArtworkComments(r *http.Request, id string) ([]Comment, error) { var body struct { Comments []Comment `json:"comments"` } URL := GetArtworkCommentsURL(id) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) err = json.Unmarshal([]byte(response), &body) if err != nil { @@ -209,7 +209,7 @@ func GetArtworkComments(c *http.Request, id string) ([]Comment, error) { return body.Comments, nil } -func GetRelatedArtworks(c *http.Request, id string) ([]ArtworkBrief, error) { +func GetRelatedArtworks(r *http.Request, id string) ([]ArtworkBrief, error) { var body struct { Illusts []ArtworkBrief `json:"illusts"` } @@ -217,12 +217,12 @@ func GetRelatedArtworks(c *http.Request, id string) ([]ArtworkBrief, error) { // TODO: keep the hard-coded limit? URL := GetArtworkRelatedURL(id, 96) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) err = json.Unmarshal([]byte(response), &body) if err != nil { @@ -232,11 +232,11 @@ func GetRelatedArtworks(c *http.Request, id string) ([]ArtworkBrief, error) { return body.Illusts, nil } -func GetArtworkByID(c *http.Request, id string, full bool) (*Illust, error) { +func GetArtworkByID(r *http.Request, id string, full bool) (*Illust, error) { URL := GetArtworkInformationURL(id) - token := session.GetPixivToken(c) - response, err := UnwrapWebAPIRequest(c.Context(), URL, token) + token := session.GetPixivToken(r) + response, err := UnwrapWebAPIRequest(r.Context(), URL, token) if err != nil { return nil, err } @@ -270,7 +270,7 @@ func GetArtworkByID(c *http.Request, id string, full bool) (*Illust, error) { go func() { // Get illust images defer wg.Done() - images, err := GetArtworkImages(c, id) + images, err := GetArtworkImages(r, id) if err != nil { cerr <- err @@ -283,7 +283,7 @@ func GetArtworkByID(c *http.Request, id string, full bool) (*Illust, error) { // Get basic user information (the URL above does not contain avatars) defer wg.Done() var err error - userInfo, err := GetUserBasicInformation(c, illust.UserID) + userInfo, err := GetUserBasicInformation(r, illust.UserID) if err != nil { cerr <- err return @@ -340,7 +340,7 @@ func GetArtworkByID(c *http.Request, id string, full bool) (*Illust, error) { idsString += fmt.Sprintf("&ids[]=%d", ids[i]) } - recent, err := GetUserArtworks(c, illust.UserID, idsString) + recent, err := GetUserArtworks(r, illust.UserID, idsString) if err != nil { cerr <- err return @@ -356,7 +356,7 @@ func GetArtworkByID(c *http.Request, id string, full bool) (*Illust, error) { go func() { defer wg.Done() var err error - related, err := GetRelatedArtworks(c, id) + related, err := GetRelatedArtworks(r, id) if err != nil { cerr <- err return @@ -370,7 +370,7 @@ func GetArtworkByID(c *http.Request, id string, full bool) (*Illust, error) { return } var err error - comments, err := GetArtworkComments(c, id) + comments, err := GetArtworkComments(r, id) if err != nil { cerr <- err return diff --git a/core/discovery.go b/core/discovery.go index a69b9d4..0c6e72a 100644 --- a/core/discovery.go +++ b/core/discovery.go @@ -5,22 +5,22 @@ import ( "codeberg.org/vnpower/pixivfe/v2/session" "github.com/goccy/go-json" - "net/http" "github.com/tidwall/gjson" + "net/http" ) -func GetDiscoveryArtwork(c *http.Request, mode string) ([]ArtworkBrief, error) { - token := session.GetPixivToken(c) +func GetDiscoveryArtwork(r *http.Request, mode string) ([]ArtworkBrief, error) { + token := session.GetPixivToken(r) URL := GetDiscoveryURL(mode, 100) var artworks []ArtworkBrief - resp, err := UnwrapWebAPIRequest(c.Context(), URL, token) + resp, err := UnwrapWebAPIRequest(r.Context(), URL, token) if err != nil { return nil, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) if !gjson.Valid(resp) { return nil, fmt.Errorf("Invalid JSON: %v", resp) } @@ -34,18 +34,18 @@ func GetDiscoveryArtwork(c *http.Request, mode string) ([]ArtworkBrief, error) { return artworks, nil } -func GetDiscoveryNovels(c *http.Request, mode string) ([]NovelBrief, error) { - token := session.GetPixivToken(c) +func GetDiscoveryNovels(r *http.Request, mode string) ([]NovelBrief, error) { + token := session.GetPixivToken(r) URL := GetDiscoveryNovelURL(mode, 100) var novels []NovelBrief - resp, err := UnwrapWebAPIRequest(c.Context(), URL, token) + resp, err := UnwrapWebAPIRequest(r.Context(), URL, token) if err != nil { return nil, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) if !gjson.Valid(resp) { return nil, fmt.Errorf("Invalid JSON: %v", resp) } diff --git a/core/index.go b/core/index.go index dbd34bf..b0b1a79 100644 --- a/core/index.go +++ b/core/index.go @@ -5,8 +5,8 @@ import ( "codeberg.org/vnpower/pixivfe/v2/session" "github.com/goccy/go-json" - "net/http" "github.com/tidwall/gjson" + "net/http" ) type Pixivision struct { @@ -31,7 +31,7 @@ type LandingArtworks struct { RecommendByTags []RecommendedTags } -func GetLanding(c *http.Request, mode string) (*LandingArtworks, error) { +func GetLanding(r *http.Request, mode string) (*LandingArtworks, error) { var pages struct { Pixivision []Pixivision `json:"pixivision"` Follow []int `json:"follow"` @@ -51,12 +51,12 @@ func GetLanding(c *http.Request, mode string) (*LandingArtworks, error) { var landing LandingArtworks - resp, err := UnwrapWebAPIRequest(c.Context(), URL, "") + resp, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return &landing, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) if !gjson.Valid(resp) { return nil, fmt.Errorf("Invalid JSON: %v", resp) diff --git a/core/newest.go b/core/newest.go index cd42322..a2fdc03 100644 --- a/core/newest.go +++ b/core/newest.go @@ -6,8 +6,8 @@ import ( "net/http" ) -func GetNewestArtworks(c *http.Request, worktype string, r18 string) ([]ArtworkBrief, error) { - token := session.GetPixivToken(c) +func GetNewestArtworks(r *http.Request, worktype string, r18 string) ([]ArtworkBrief, error) { + token := session.GetPixivToken(r) URL := GetNewestArtworksURL(worktype, r18, "0") var body struct { @@ -15,11 +15,11 @@ func GetNewestArtworks(c *http.Request, worktype string, r18 string) ([]ArtworkB // LastId string } - resp, err := UnwrapWebAPIRequest(c.Context(), URL, token) + resp, err := UnwrapWebAPIRequest(r.Context(), URL, token) if err != nil { return nil, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) err = json.Unmarshal([]byte(resp), &body) if err != nil { diff --git a/core/novel.go b/core/novel.go index ce06160..daf6d58 100644 --- a/core/novel.go +++ b/core/novel.go @@ -11,30 +11,30 @@ import ( ) type Novel struct { - Bookmarks int `json:"bookmarkCount"` - CommentCount int `json:"commentCount"` - MarkerCount int `json:"markerCount"` - CreateDate time.Time `json:"createDate"` - UploadDate time.Time `json:"uploadDate"` - Description string `json:"description"` - ID string `json:"id"` - Title string `json:"title"` - Likes int `json:"likeCount"` - Pages int `json:"pageCount"` - UserID string `json:"userId"` - UserName string `json:"userName"` - Views int `json:"viewCount"` - IsOriginal bool `json:"isOriginal"` - IsBungei bool `json:"isBungei"` - XRestrict int `json:"xRestrict"` - Restrict int `json:"restrict"` - Content string `json:"content"` - CoverURL string `json:"coverUrl"` - IsBookmarkable bool `json:"isBookmarkable"` - BookmarkData any `json:"bookmarkData"` - LikeData bool `json:"likeData"` - PollData any `json:"pollData"` - Marker any `json:"marker"` + Bookmarks int `json:"bookmarkCount"` + CommentCount int `json:"commentCount"` + MarkerCount int `json:"markerCount"` + CreateDate time.Time `json:"createDate"` + UploadDate time.Time `json:"uploadDate"` + Description string `json:"description"` + ID string `json:"id"` + Title string `json:"title"` + Likes int `json:"likeCount"` + Pages int `json:"pageCount"` + UserID string `json:"userId"` + UserName string `json:"userName"` + Views int `json:"viewCount"` + IsOriginal bool `json:"isOriginal"` + IsBungei bool `json:"isBungei"` + XRestrict int `json:"xRestrict"` + Restrict int `json:"restrict"` + Content string `json:"content"` + CoverURL string `json:"coverUrl"` + IsBookmarkable bool `json:"isBookmarkable"` + BookmarkData any `json:"bookmarkData"` + LikeData bool `json:"likeData"` + PollData any `json:"pollData"` + Marker any `json:"marker"` Tags struct { AuthorID string `json:"authorId"` IsLocked bool `json:"isLocked"` @@ -43,9 +43,9 @@ type Novel struct { } `json:"tags"` Writable bool `json:"writable"` } `json:"tags"` - SeriesNavData any `json:"seriesNavData"` - HasGlossary bool `json:"hasGlossary"` - IsUnlisted bool `json:"isUnlisted"` + SeriesNavData any `json:"seriesNavData"` + HasGlossary bool `json:"hasGlossary"` + IsUnlisted bool `json:"isUnlisted"` // seen values: zh-cn, ja Language string `json:"language"` CommentOff int `json:"commentOff"` @@ -62,43 +62,43 @@ type Novel struct { } type NovelBrief struct { - ID string `json:"id"` - Title string `json:"title"` - XRestrict int `json:"xRestrict"` - Restrict int `json:"restrict"` - CoverURL string `json:"url"` - Tags []string `json:"tags"` - UserID string `json:"userId"` - UserName string `json:"userName"` - UserAvatar string `json:"profileImageUrl"` - TextCount int `json:"textCount"` - WordCount int `json:"wordCount"` - ReadingTime int `json:"readingTime"` - Description string `json:"description"` - IsBookmarkable bool `json:"isBookmarkable"` - BookmarkData any `json:"bookmarkData"` - Bookmarks int `json:"bookmarkCount"` - IsOriginal bool `json:"isOriginal"` - CreateDate time.Time `json:"createDate"` - UpdateDate time.Time `json:"updateDate"` - IsMasked bool `json:"isMasked"` - SeriesID string `json:"seriesId"` - SeriesTitle string `json:"seriesTitle"` - IsUnlisted bool `json:"isUnlisted"` - AiType int `json:"aiType"` - Genre string `json:"genre"` + ID string `json:"id"` + Title string `json:"title"` + XRestrict int `json:"xRestrict"` + Restrict int `json:"restrict"` + CoverURL string `json:"url"` + Tags []string `json:"tags"` + UserID string `json:"userId"` + UserName string `json:"userName"` + UserAvatar string `json:"profileImageUrl"` + TextCount int `json:"textCount"` + WordCount int `json:"wordCount"` + ReadingTime int `json:"readingTime"` + Description string `json:"description"` + IsBookmarkable bool `json:"isBookmarkable"` + BookmarkData any `json:"bookmarkData"` + Bookmarks int `json:"bookmarkCount"` + IsOriginal bool `json:"isOriginal"` + CreateDate time.Time `json:"createDate"` + UpdateDate time.Time `json:"updateDate"` + IsMasked bool `json:"isMasked"` + SeriesID string `json:"seriesId"` + SeriesTitle string `json:"seriesTitle"` + IsUnlisted bool `json:"isUnlisted"` + AiType int `json:"aiType"` + Genre string `json:"genre"` } -func GetNovelByID(c *http.Request, id string) (Novel, error) { +func GetNovelByID(r *http.Request, id string) (Novel, error) { var novel Novel URL := GetNovelURL(id) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return novel, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) err = json.Unmarshal([]byte(response), &novel) if err != nil { @@ -106,21 +106,21 @@ func GetNovelByID(c *http.Request, id string) (Novel, error) { } // Novel embedded illusts - r := regexp.MustCompile("\\[pixivimage:(\\d+.\\d+)\\]") - d := regexp.MustCompile("\\d+.\\d+") - t := regexp.MustCompile(`\"original\":\"(.+?)\"`) + re_r := regexp.MustCompile("\\[pixivimage:(\\d+.\\d+)\\]") + re_d := regexp.MustCompile("\\d+.\\d+") + re_t := regexp.MustCompile(`\"original\":\"(.+?)\"`) - novel.Content = r.ReplaceAllStringFunc(novel.Content, func(s string) string { - illustid := d.FindString(s) + novel.Content = re_r.ReplaceAllStringFunc(novel.Content, func(s string) string { + illustid := re_d.FindString(s) URL := GetInsertIllustURL(novel.ID, illustid) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return "Cannot insert illust" + illustid } - url := t.FindString(response) - url = session.ProxyImageUrl(c, url[11:]) // truncate the "original": + url := re_t.FindString(response) + url = session.ProxyImageUrl(r, url[11:]) // truncate the "original": return fmt.Sprintf(`%s`, url, s) }) @@ -128,7 +128,7 @@ func GetNovelByID(c *http.Request, id string) (Novel, error) { return novel, nil } -func GetNovelRelated(c *http.Request, id string) ([]NovelBrief, error) { +func GetNovelRelated(r *http.Request, id string) ([]NovelBrief, error) { var novels struct { List []NovelBrief `json:"novels"` } @@ -136,11 +136,11 @@ func GetNovelRelated(c *http.Request, id string) ([]NovelBrief, error) { // hard-coded value, may change URL := GetNovelRelatedURL(id, 50) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return novels.List, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) err = json.Unmarshal([]byte(response), &novels) if err != nil { diff --git a/core/personal.go b/core/personal.go index 36c0f4e..a475441 100644 --- a/core/personal.go +++ b/core/personal.go @@ -7,8 +7,8 @@ import ( "net/http" ) -func GetNewestFromFollowing(c *http.Request, mode, page string) ([]ArtworkBrief, error) { - token := session.GetPixivToken(c) +func GetNewestFromFollowing(r *http.Request, mode, page string) ([]ArtworkBrief, error) { + token := session.GetPixivToken(r) URL := GetNewestFromFollowingURL(mode, page) var body struct { @@ -19,11 +19,11 @@ func GetNewestFromFollowing(c *http.Request, mode, page string) ([]ArtworkBrief, Artworks []ArtworkBrief `json:"illust"` } - resp, err := UnwrapWebAPIRequest(c.Context(), URL, token) + resp, err := UnwrapWebAPIRequest(r.Context(), URL, token) if err != nil { return nil, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) err = json.Unmarshal([]byte(resp), &body) if err != nil { diff --git a/core/ranking.go b/core/ranking.go index 77e7158..6d173da 100644 --- a/core/ranking.go +++ b/core/ranking.go @@ -34,16 +34,16 @@ type Ranking struct { NextDate string } -func GetRanking(c *http.Request, mode, content, date, page string) (Ranking, error) { +func GetRanking(r *http.Request, mode, content, date, page string) (Ranking, error) { URL := GetRankingURL(mode, content, date, page) var ranking Ranking - resp := WebAPIRequest(c.Context(), URL, "") + resp := WebAPIRequest(r.Context(), URL, "") if !resp.Ok { return ranking, errors.New(resp.Message) } - proxiedResp := session.ProxyImageUrl(c, resp.Body) + proxiedResp := session.ProxyImageUrl(r, resp.Body) err := json.Unmarshal([]byte(proxiedResp), &ranking) if err != nil { diff --git a/core/rankingCalendar.go b/core/rankingCalendar.go index 645096f..f523b3d 100644 --- a/core/rankingCalendar.go +++ b/core/rankingCalendar.go @@ -34,15 +34,15 @@ func get_weekday(n time.Weekday) int { // note(@iacore): // so the funny thing about Pixiv is that they will return this month's data for a request of a future date // is it a bug or a feature? -func GetRankingCalendar(c *http.Request, mode string, year, month int) (template.HTML, error) { - token := session.GetPixivToken(c) +func GetRankingCalendar(r *http.Request, mode string, year, month int) (template.HTML, error) { + token := session.GetPixivToken(r) URL := GetRankingCalendarURL(mode, year, month) req, err := http.NewRequest("GET", URL, nil) if err != nil { return template.HTML(""), err } - req = req.WithContext(c.Context()) + req = req.WithContext(r.Context()) req.Header.Add("User-Agent", "Mozilla/5.0") req.Header.Add("Cookie", "PHPSESSID="+token) // req.AddCookie(&http.Cookie{ @@ -70,19 +70,19 @@ func GetRankingCalendar(c *http.Request, mode string, year, month int) (template for _, a := range n.Attr { if a.Key == "data-src" { // adds a new link entry when the attribute matches - links = append(links, session.ProxyImageUrlNoEscape(c, a.Val)) + links = append(links, session.ProxyImageUrlNoEscape(r, a.Val)) } } } // traverses the HTML of the webpage from the first child node - for c := n.FirstChild; c != nil; c = c.NextSibling { - link(c) + for r := n.FirstChild; r != nil; r = r.NextSibling { + link(r) } } link(doc) - // now := c.Context().Time() + // now := r.Context().Time() // yearNow := now.Year() // monthNow := now.Month() lastMonth := time.Date(year, time.Month(month), 0, 0, 0, 0, 0, time.UTC) diff --git a/core/tag.go b/core/tag.go index 63f37ad..c3add55 100644 --- a/core/tag.go +++ b/core/tag.go @@ -71,17 +71,17 @@ func (s SearchPageSettings) ReturnMap() map[string]string { } } -func GetTagData(c *http.Request, name string) (TagDetail, error) { +func GetTagData(r *http.Request, name string) (TagDetail, error) { var tag TagDetail URL := GetTagDetailURL(name) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return tag, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) err = json.Unmarshal([]byte(response), &tag) if err != nil { @@ -91,14 +91,14 @@ func GetTagData(c *http.Request, name string) (TagDetail, error) { return tag, nil } -func GetSearch(c *http.Request, settings SearchPageSettings) (*SearchResult, error) { +func GetSearch(r *http.Request, settings SearchPageSettings) (*SearchResult, error) { URL := GetSearchArtworksURL(settings.ReturnMap()) - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, err } - response = session.ProxyImageUrl(c, response) + response = session.ProxyImageUrl(r, response) // IDK how to do better than this lol temp := strings.ReplaceAll(string(response), `"illust"`, `"works"`) diff --git a/core/user.go b/core/user.go index b88f8df..45b4ae5 100644 --- a/core/user.go +++ b/core/user.go @@ -43,17 +43,17 @@ type FrequentTag struct { } 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]any `json:"background"` + 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]any `json:"background"` ArtworksCount int FrequentTags []FrequentTag Social map[string]map[string]string @@ -73,7 +73,7 @@ func (s *User) ParseSocial() error { return nil } -func GetFrequentTags(c *http.Request, ids string, category UserArtCategory) ([]FrequentTag, error) { +func GetFrequentTags(r *http.Request, ids string, category UserArtCategory) ([]FrequentTag, error) { var tags []FrequentTag var URL string @@ -83,7 +83,7 @@ func GetFrequentTags(c *http.Request, ids string, category UserArtCategory) ([]F URL = GetFrequentNovelTagsURL(ids) } - response, err := UnwrapWebAPIRequest(c.Context(), URL, "") + response, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, err } @@ -96,16 +96,16 @@ func GetFrequentTags(c *http.Request, ids string, category UserArtCategory) ([]F return tags, nil } -func GetUserArtworks(c *http.Request, id, ids string) ([]ArtworkBrief, error) { +func GetUserArtworks(r *http.Request, id, ids string) ([]ArtworkBrief, error) { var works []ArtworkBrief URL := GetUserFullArtworkURL(id, ids) - resp, err := UnwrapWebAPIRequest(c.Context(), URL, "") + resp, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) var body struct { Illusts map[int]json.RawMessage `json:"works"` @@ -130,17 +130,17 @@ func GetUserArtworks(c *http.Request, id, ids string) ([]ArtworkBrief, error) { return works, nil } -func GetUserNovels(c *http.Request, id, ids string) ([]NovelBrief, error) { +func GetUserNovels(r *http.Request, 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 := GetUserFullNovelURL(id, ids) - resp, err := UnwrapWebAPIRequest(c.Context(), URL, "") + resp, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) var body struct { Novels map[int]json.RawMessage `json:"works"` @@ -165,10 +165,10 @@ func GetUserNovels(c *http.Request, id, ids string) ([]NovelBrief, error) { return works, nil } -func GetUserArtworksID(c *http.Request, id string, category UserArtCategory, page int) (string, int, error) { +func GetUserArtworksID(r *http.Request, id string, category UserArtCategory, page int) (string, int, error) { URL := GetUserArtworksURL(id) - resp, err := UnwrapWebAPIRequest(c.Context(), URL, "") + resp, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return "", -1, err } @@ -248,19 +248,19 @@ func GetUserArtworksID(c *http.Request, id string, category UserArtCategory, pag return idsString, count, nil } -func GetUserArtwork(c *http.Request, id string, category UserArtCategory, page int, getTags bool) (User, error) { +func GetUserArtwork(r *http.Request, id string, category UserArtCategory, page int, getTags bool) (User, error) { var user User - token := session.GetPixivToken(c) + token := session.GetPixivToken(r) URL := GetUserInformationURL(id) - resp, err := UnwrapWebAPIRequest(c.Context(), URL, token) + resp, err := UnwrapWebAPIRequest(r.Context(), URL, token) if err != nil { return user, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) err = json.Unmarshal([]byte(resp), &user) if err != nil { @@ -269,7 +269,7 @@ func GetUserArtwork(c *http.Request, id string, category UserArtCategory, page i if category == UserArt_Bookmarks { // Bookmarks - works, count, err := GetUserBookmarks(c, id, "show", page) + works, count, err := GetUserBookmarks(r, id, "show", page) if err != nil { return user, err } @@ -279,14 +279,14 @@ func GetUserArtwork(c *http.Request, id string, category UserArtCategory, page i // Public bookmarks count user.ArtworksCount = count } else if category == UserArt_Novel { - ids, count, err := GetUserArtworksID(c, id, category, page) + ids, count, err := GetUserArtworksID(r, 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) + works, err := GetUserNovels(r, id, ids) if err != nil { return user, err } @@ -300,7 +300,7 @@ func GetUserArtwork(c *http.Request, id string, category UserArtCategory, page i user.Novels = works if getTags { - user.FrequentTags, err = GetFrequentTags(c, ids, category) + user.FrequentTags, err = GetFrequentTags(r, ids, category) if err != nil { return user, err } @@ -310,14 +310,14 @@ func GetUserArtwork(c *http.Request, id string, category UserArtCategory, page i // Artworks count user.ArtworksCount = count } else { - ids, count, err := GetUserArtworksID(c, id, category, page) + ids, count, err := GetUserArtworksID(r, 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) + works, err := GetUserArtworks(r, id, ids) if err != nil { return user, err } @@ -331,7 +331,7 @@ func GetUserArtwork(c *http.Request, id string, category UserArtCategory, page i user.Artworks = works if getTags { - user.FrequentTags, err = GetFrequentTags(c, ids, category) + user.FrequentTags, err = GetFrequentTags(r, ids, category) if err != nil { return user, err } @@ -354,16 +354,16 @@ func GetUserArtwork(c *http.Request, id string, category UserArtCategory, page i return user, nil } -func GetUserBookmarks(c *http.Request, id, mode string, page int) ([]ArtworkBrief, int, error) { +func GetUserBookmarks(r *http.Request, id, mode string, page int) ([]ArtworkBrief, int, error) { page-- URL := GetUserBookmarksURL(id, mode, page) - resp, err := UnwrapWebAPIRequest(c.Context(), URL, "") + resp, err := UnwrapWebAPIRequest(r.Context(), URL, "") if err != nil { return nil, -1, err } - resp = session.ProxyImageUrl(c, resp) + resp = session.ProxyImageUrl(r, resp) var body struct { Artworks []json.RawMessage `json:"works"` diff --git a/doc/dev/framework-migration.md b/doc/dev/framework-migration.md index b5bc4a0..92269fa 100644 --- a/doc/dev/framework-migration.md +++ b/doc/dev/framework-migration.md @@ -15,8 +15,12 @@ net/http handlers don't return errors. We have to make our own ServeMux that allows functions to return `error`, possibly. +net/http expects handlers to panic on error, while we don't panic. We need to log the errors anyway. + +Idea: we create a compat layer of {w, r} that has the same API as *fiber.Ctx. + ## Tips To access `/:abc`, use `r.PathValue("abc")`. -Idea: we create a compat layer of {w, r} that has the same API as *fiber.Ctx. +Want to associate arbitrary value with a request? Use `r.Context.Value()`. \ No newline at end of file diff --git a/go.mod b/go.mod index 1a05aa1..3aee8d2 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/gorilla/mux v1.8.1 github.com/stretchr/testify v1.9.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect diff --git a/go.sum b/go.sum index b36cb15..7c3c1a2 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/playwright-community/playwright-go v0.4501.1 h1:kz8SIfR6nEI8blk77nTVD0K5/i37QP5rY/o8a1fG+4c= diff --git a/main.go b/main.go index 50298e6..e936eed 100644 --- a/main.go +++ b/main.go @@ -17,16 +17,8 @@ import ( "codeberg.org/vnpower/pixivfe/v2/core" "codeberg.org/vnpower/pixivfe/v2/routes" "codeberg.org/vnpower/pixivfe/v2/session" - // "codeberg.org/vnpower/pixivfe/v2/utils/kmutex" - // "github.com/CloudyKit/jet/v6" - // "github.com/goccy/go-json" - // "net/http" - // "net/http/middleware/cache" - // "net/http/middleware/compress" - // "net/http/middleware/limiter" - // "net/http/middleware/logger" - // "net/http/middleware/recover" - // fiber_utils "net/http/utils" + + "github.com/gorilla/mux" ) func CanRequestSkipLimiter(r *http.Request) bool { @@ -44,6 +36,18 @@ func CanRequestSkipLogger(r *http.Request) bool { strings.HasPrefix(path, "/proxy/i.pximg.net/") } +type UserContext struct { + err error +} + +type userContextKey struct{} + +var UserContextKey = userContextKey{} + +func GetUserContext(r *http.Request) *UserContext { + return r.Context().Value(UserContextKey).(*UserContext) +} + func main() { config.GlobalServerConfig.InitializeConfig() if config.GlobalServerConfig.InDevelopment { @@ -60,7 +64,7 @@ func main() { // EnableTrustedProxyCheck: true, // TrustedProxies: []string{"0.0.0.0/0"}, // ProxyHeader: fiber.HeaderXForwardedFor, - // ErrorHandler: func(c *http.Request, err error) error { + // ErrorHandler: func(r *http.Request, err error) error { // log.Println(err) // // Status code defaults to 500 @@ -73,10 +77,10 @@ func main() { // // } // // Send custom error page - // c.Status(code) - // err = routes.Render(c, routes.Data_error{Title: "Error", Error: err}) + // r.Status(code) + // err = routes.Render(w, r, routes.Data_error{Title: "Error", Error: err}) // if err != nil { - // return c.Status(code).SendString(fmt.Sprintf("Internal Server Error: %s", err)) + // return r.Status(code).SendString(fmt.Sprintf("Internal Server Error: %s", err)) // } // return nil @@ -91,23 +95,23 @@ func main() { // Expiration: 30 * time.Second, // Max: config.GlobalServerConfig.RequestLimit, // LimiterMiddleware: limiter.SlidingWindow{}, - // LimitReached: func(c *http.Request) error { + // LimitReached: func(r *http.Request) error { // // limit response throughput by pacing, since not every bot reads X-RateLimit-* // // on limit reached, they just have to wait // // the design of this means that if they send multiple requests when reaching rate limit, they will wait even longer (since `retryAfter` is calculated before anything has slept) - // retryAfter_s := c.GetRespHeader(fiber.HeaderRetryAfter) + // retryAfter_s := r.GetRespHeader(fiber.HeaderRetryAfter) // retryAfter, err := strconv.ParseUint(retryAfter_s, 10, 64) // if err != nil { // log.Panicf("response header 'RetryAfter' should be a number: %v", err) // } - // requestIP := c.IP() + // requestIP := r.IP() // refcount := keyedSleepingSpot.Lock(requestIP) // defer keyedSleepingSpot.Unlock(requestIP) // if refcount >= 4 { // on too much concurrent requests // // todo: maybe blackhole `requestIP` here // log.Println("Limit Reached (Hard)!", requestIP) // // close the connection immediately - // _ = c.Context().Conn().Close() + // _ = r.Context().Conn().Close() // return nil // } @@ -116,11 +120,11 @@ func main() { // // todo: close this connection when this IP reaches hard limit // dur := time.Duration(retryAfter) * time.Second // log.Println("Limit Reached (Soft)! Sleeping for ", dur) - // ctx, cancel := context.WithTimeout(c.Context(), dur) + // ctx, cancel := context.WithTimeout(r.Context(), dur) // defer cancel() // <-ctx.Done() - // return c.Next() + // return r.Next() // }, // })) // } @@ -129,23 +133,23 @@ func main() { // if !config.GlobalServerConfig.InDevelopment { // server.Use(cache.New( // cache.Config{ - // Next: func(c *http.Request) bool { - // resp_code := c.Response().StatusCode() + // Next: func(r *http.Request) bool { + // resp_code := r.Response().StatusCode() // if resp_code < 200 || resp_code >= 300 { // return true // } // // Disable cache for settings page - // return strings.Contains(c.Path(), "/settings") || c.Path() == "/" + // return strings.Contains(r.Path(), "/settings") || r.Path() == "/" // }, // Expiration: 5 * time.Minute, // CacheControl: true, // StoreResponseHeaders: true, - // KeyGenerator: func(c *http.Request) string { - // key := fiber_utils.CopyString(c.OriginalURL()) + // KeyGenerator: func(r *http.Request) string { + // key := fiber_utils.CopyString(r.OriginalURL()) // for _, cookieName := range session.AllCookieNames { - // cookieValue := session.GetCookie(c, cookieName) + // cookieValue := session.GetCookie(r, cookieName) // if cookieValue != "" { // key += "\x00\x00" // key += string(cookieName) @@ -162,9 +166,12 @@ func main() { router := defineRoutes() main_handler := func(w http.ResponseWriter, r *http.Request) { + // set user context + r = r.WithContext(context.WithValue(r.Context(), UserContextKey, &UserContext{})) + start_time := time.Now() - setGlobalHeaders(r) + setGlobalHeaders(w) router.ServeHTTP(w, r) @@ -185,10 +192,10 @@ func main() { method := r.Method path := r.URL.Path status := r.Response.Status + err := GetUserContext(r).err - log.Printf("%v +%v %v %v %v %v {todo: print error (where is error?)}", time, latency, ip, method, path, status) + log.Printf("%v +%v %v %v %v %v %v", time, latency, ip, method, path, status, err) } - } // Initialize and start the proxy checker @@ -233,10 +240,8 @@ func main() { http.Serve(l, http.HandlerFunc(main_handler)) } -// todo: if this doesn't work, need to use `w.Header()` -func setGlobalHeaders(r *http.Request) { - // Respond with global HTTP headers - header := r.Response.Header +func setGlobalHeaders(w http.ResponseWriter) { + header := w.Header() header.Add("X-Frame-Options", "DENY") // use this if need iframe: `X-Frame-Options: SAMEORIGIN` header.Add("X-Content-Type-Options", "nosniff") @@ -250,8 +255,8 @@ func setGlobalHeaders(r *http.Request) { func serveFile(filename string) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, filename) } } -func defineRoutes() http.ServeMux { - router := http.ServeMux{} +func defineRoutes() *mux.Router { + router := mux.NewRouter() router.HandleFunc("/favicon.ico", serveFile("./assets/img/favicon.ico")) router.HandleFunc("/robots.txt", serveFile("./assets/robots.txt")) @@ -259,11 +264,8 @@ func defineRoutes() http.ServeMux { router.Handle("/css/", http.FileServer(http.Dir("./assets/css"))) router.Handle("/js/", http.FileServer(http.Dir("./assets/js"))) - // server.Use(recover.New(recover.Config{EnableStackTrace: config.GlobalServerConfig.InDevelopment})) - - // // Routes - - // server.Get("/", routes.IndexPage) + // Routes + router.Get("/").Handler(CatchError(routes.IndexPage)) // server.Get("/about", routes.AboutPage) // server.Get("/newest", routes.NewestPage) // server.Get("/discovery", routes.DiscoveryPage) @@ -303,8 +305,8 @@ func defineRoutes() http.ServeMux { // server.Post("/tags", routes.AdvancedTagPost) // // Legacy illust URL - // server.Get("/member_illust.php", func(c *http.Request) error { - // return c.Redirect("/artworks/" + c.Query("illust_id")) + // server.Get("/member_illust.php", func(r *http.Request) error { + // return r.Redirect("/artworks/" + r.Query("illust_id")) // }) // // Proxy routes @@ -315,3 +317,9 @@ func defineRoutes() http.ServeMux { return router } + +func CatchError(handler func(w http.ResponseWriter, r routes.CompatRequest) error) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + GetUserContext(r).err = handler(w, routes.CompatRequest{Request: r}) + } +} diff --git a/routes/about.go b/routes/about.go index 75c603f..e701492 100644 --- a/routes/about.go +++ b/routes/about.go @@ -5,8 +5,8 @@ import ( "net/http" ) -func AboutPage(c *http.Request) error { - return Render(c, Data_about{ +func AboutPage(w http.ResponseWriter, r CompatRequest) error { + return Render(w, r, Data_about{ Time: config.GlobalServerConfig.StartingTime, Version: config.GlobalServerConfig.Version, ImageProxy: config.GlobalServerConfig.ProxyServer.String(), diff --git a/routes/actions.go b/routes/actions.go index ebdfe33..a911deb 100644 --- a/routes/actions.go +++ b/routes/actions.go @@ -11,14 +11,14 @@ import ( "github.com/tidwall/gjson" ) -func pixivPostRequest(c *http.Request, url, payload, token, csrf string, isJSON bool) error { +func pixivPostRequest(r *fiber.Ctx, url, payload, token, csrf string, isJSON bool) error { requestBody := []byte(payload) req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody)) if err != nil { return err } - req = req.WithContext(c.Context()) + req = req.WithContext(r.Context()) req.Header.Add("User-Agent", "Mozilla/5.0") req.Header.Add("Accept", "application/json") req.Header.Add("Cookie", "PHPSESSID="+token) @@ -59,15 +59,15 @@ func pixivPostRequest(c *http.Request, url, payload, token, csrf string, isJSON return nil } -func AddBookmarkRoute(c *http.Request) error { - token := session.GetPixivToken(c) - csrf := session.GetCookie(c, session.Cookie_CSRF) +func AddBookmarkRoute(w http.ResponseWriter, r CompatRequest) error { + token := session.GetPixivToken(r) + csrf := session.GetCookie(r, session.Cookie_CSRF) if token == "" || csrf == "" { - return PromptUserToLoginPage(c) + return PromptUserToLoginPage(r) } - id := c.Params("id") + id := r.Params("id") if id == "" { return errors.New("No ID provided.") } @@ -79,22 +79,22 @@ func AddBookmarkRoute(c *http.Request) error { "comment": "", "tags": [] }`, id) - if err := pixivPostRequest(c, URL, payload, token, csrf, true); err != nil { + if err := pixivPostRequest(r, URL, payload, token, csrf, true); err != nil { return err } - return c.SendString("Success") + return r.SendString("Success") } -func DeleteBookmarkRoute(c *http.Request) error { - token := session.GetPixivToken(c) - csrf := session.GetCookie(c, session.Cookie_CSRF) +func DeleteBookmarkRoute(w http.ResponseWriter, r CompatRequest) error { + token := session.GetPixivToken(r) + csrf := session.GetCookie(r, session.Cookie_CSRF) if token == "" || csrf == "" { - return PromptUserToLoginPage(c) + return PromptUserToLoginPage(r) } - id := c.Params("id") + id := r.Params("id") if id == "" { return errors.New("No ID provided.") } @@ -102,31 +102,31 @@ func DeleteBookmarkRoute(c *http.Request) error { // You can't unlike URL := "https://www.pixiv.net/ajax/illusts/bookmarks/delete" payload := fmt.Sprintf(`bookmark_id=%s`, id) - if err := pixivPostRequest(c, URL, payload, token, csrf, false); err != nil { + if err := pixivPostRequest(r, URL, payload, token, csrf, false); err != nil { return err } - return c.SendString("Success") + return r.SendString("Success") } -func LikeRoute(c *http.Request) error { - token := session.GetPixivToken(c) - csrf := session.GetCookie(c, session.Cookie_CSRF) +func LikeRoute(w http.ResponseWriter, r CompatRequest) error { + token := session.GetPixivToken(r) + csrf := session.GetCookie(r, session.Cookie_CSRF) if token == "" || csrf == "" { - return PromptUserToLoginPage(c) + return PromptUserToLoginPage(r) } - id := c.Params("id") + id := r.Params("id") if id == "" { return errors.New("No ID provided.") } URL := "https://www.pixiv.net/ajax/illusts/like" payload := fmt.Sprintf(`{"illust_id": "%s"}`, id) - if err := pixivPostRequest(c, URL, payload, token, csrf, true); err != nil { + if err := pixivPostRequest(r, URL, payload, token, csrf, true); err != nil { return err } - return c.SendString("Success") + return r.SendString("Success") } diff --git a/routes/artwork.go b/routes/artwork.go index afcecc0..2daad80 100644 --- a/routes/artwork.go +++ b/routes/artwork.go @@ -8,13 +8,13 @@ import ( "net/http" ) -func ArtworkPage(c *http.Request) error { - id := c.Params("id") +func ArtworkPage(w http.ResponseWriter, r CompatRequest) error { + id := r.Params("id") if _, err := strconv.Atoi(id); err != nil { return fmt.Errorf("Invalid ID: %s", id) } - illust, err := core.GetArtworkByID(c, id, true) + illust, err := core.GetArtworkByID(r, id, true) if err != nil { return err } @@ -26,10 +26,10 @@ func ArtworkPage(c *http.Request) error { // monkey patching. assuming illust.Images[_].Large is used for _, img := range illust.Images { - PreloadImage(c, img.Large) + PreloadImage(r, img.Large) } - return Render(c, Data_artwork{ + return Render(w, r, Data_artwork{ Illust: *illust, Title: illust.Title, MetaDescription: metaDescription, @@ -39,6 +39,6 @@ func ArtworkPage(c *http.Request) error { }) } -func PreloadImage(c *http.Request, url string) { - c.Response().Header.Add("Link", fmt.Sprintf("<%s>; rel=preload; as=image", url)) +func PreloadImage(r *fiber.Ctx, url string) { + r.Response().Header.Add("Link", fmt.Sprintf("<%s>; rel=preload; as=image", url)) } diff --git a/routes/artworkMulti.go b/routes/artworkMulti.go index 9a8c97d..4af6c0f 100644 --- a/routes/artworkMulti.go +++ b/routes/artworkMulti.go @@ -10,19 +10,19 @@ import ( "net/http" ) -func ArtworkMultiPage(c *http.Request) error { - ids_ := c.Params("ids") +func ArtworkMultiPage(w http.ResponseWriter, r CompatRequest) error { + ids_ := r.Params("ids") ids := strings.Split(ids_, ",") artworks := make([]core.Illust, len(ids)) wg := sync.WaitGroup{} // // gofiber/fasthttp's API is trash - // // i can't replace c.Context() with this + // // i can't replace r.Context() with this // // so i guess we will have to wait for network traffic to finish on error - // ctx, cancel := context.WithCancel(c.Context()) + // ctx, cancel := context.WithCancel(r.Context()) // defer cancel() - // c.SetUserContext(ctx) + // r.SetUserContext(ctx) var err_global error = nil for i, id := range ids { if _, err := strconv.Atoi(id); err != nil { @@ -34,7 +34,7 @@ func ArtworkMultiPage(c *http.Request) error { go func(i int, id string) { defer wg.Done() - illust, err := core.GetArtworkByID(c, id, false) + illust, err := core.GetArtworkByID(r, id, false) if err != nil { artworks[i] = core.Illust{ Title: err.Error(), // this might be flaky @@ -58,7 +58,7 @@ func ArtworkMultiPage(c *http.Request) error { return err_global } - return Render(c, Data_artworkMulti{ + return Render(w, r, Data_artworkMulti{ Artworks: artworks, Title: fmt.Sprintf("(%d images)", len(artworks)), }) diff --git a/routes/compat.go b/routes/compat.go new file mode 100644 index 0000000..bf795f1 --- /dev/null +++ b/routes/compat.go @@ -0,0 +1,60 @@ +package routes + +import ( + "net/http" + "net/url" + + "github.com/gorilla/mux" +) + +type CompatRequest struct { + *http.Request +} + +func (r CompatRequest) BaseURL() string { + return (&url.URL{ + Scheme: r.URL.Scheme, + Opaque: r.URL.Opaque, + User: r.URL.User, + Host: r.URL.Host, + }).String() +} +func (r CompatRequest) OriginalURL() string { + return (&url.URL{ + Path: r.URL.Path, + RawPath: r.URL.RawPath, + OmitHost: r.URL.OmitHost, + ForceQuery: r.URL.ForceQuery, + RawQuery: r.URL.RawQuery, + Fragment: r.URL.Fragment, + RawFragment: r.URL.RawFragment, + }).String() +} +func (r CompatRequest) PageURL() string { + return r.URL.String() +} + +func (r CompatRequest) Query(name string, defaultValue ...string) string { + if v := r.URL.Query().Get(name); v != "" { + return v + } else { + if len(defaultValue) == 0 { + return "" + } else { + return defaultValue[0] + } + } +} + +// get path segment. no idea why it's called "params" +func (r CompatRequest) Params(name string, defaultValue ...string) string { + if v := mux.Vars(r.Request)[name]; v != "" { + return v + } else { + if len(defaultValue) == 0 { + return "" + } else { + return defaultValue[0] + } + } +} diff --git a/routes/discovery.go b/routes/discovery.go index 21dd3b5..ed4cf88 100644 --- a/routes/discovery.go +++ b/routes/discovery.go @@ -6,26 +6,26 @@ import ( "net/http" ) -func DiscoveryPage(c *http.Request) error { - mode := c.Query("mode", "safe") +func DiscoveryPage(w http.ResponseWriter, r CompatRequest) error { + mode := r.Query("mode", "safe") - works, err := core.GetDiscoveryArtwork(c, mode) + works, err := core.GetDiscoveryArtwork(r, mode) if err != nil { return err } urlc := utils.PartialURL{Path: "discovery", Query: map[string]string{"mode": mode}} - return Render(c, Data_discovery{Artworks: works, Title: "Discovery", Queries: urlc}) + return Render(w, r, Data_discovery{Artworks: works, Title: "Discovery", Queries: urlc}) } -func NovelDiscoveryPage(c *http.Request) error { - mode := c.Query("mode", "safe") +func NovelDiscoveryPage(w http.ResponseWriter, r CompatRequest) error { + mode := r.Query("mode", "safe") - works, err := core.GetDiscoveryNovels(c, mode) + works, err := core.GetDiscoveryNovels(r, mode) if err != nil { return err } - return Render(c, Data_novelDiscovery{Novels: works, Title: "Discovery"}) + return Render(w, r, Data_novelDiscovery{Novels: works, Title: "Discovery"}) } diff --git a/routes/index.go b/routes/index.go index 33f1ca8..e265ae0 100644 --- a/routes/index.go +++ b/routes/index.go @@ -1,46 +1,47 @@ package routes import ( + "net/http" + "codeberg.org/vnpower/pixivfe/v2/core" "codeberg.org/vnpower/pixivfe/v2/session" "net/http" ) -func IndexPage(c *http.Request) error { - +func IndexPage(w http.ResponseWriter, r CompatRequest) error { // If token is set, do the landing request... - if token := session.GetPixivToken(c); token != "" { - mode := c.Query("mode", "all") + if token := session.GetPixivToken(r); token != "" { + mode := r.Query("mode", "all") - works, err := core.GetLanding(c, mode) + works, err := core.GetLanding(r, mode) if err != nil { return err } - return Render(c, Data_index{ - Title: "Landing", - Data: *works, + return Render(w, r, Data_index{ + Title: "Landing", + Data: *works, LoggedIn: true, }) } // ...otherwise, default to today's illustration ranking - works, err := core.GetRanking(c, "daily", "illust", "", "1") + works, err := core.GetRanking(r, "daily", "illust", "", "1") if err != nil { return err } - return Render(c, Data_index{ + return Render(w, r, Data_index{ Title: "Landing", NoTokenData: works, - LoggedIn: false, + LoggedIn: false, }) } -func Oembed(c *http.Request) error { - pageURL := c.BaseURL() - artistName := c.Query("a", "") - artistURL := c.Query("u", "") +func Oembed(w http.ResponseWriter, r CompatRequest) error { + pageURL := r.BaseURL() + artistName := r.Query("a", "") + artistURL := r.Query("u", "") data := fiber.Map{ "version": "1.0", @@ -51,5 +52,5 @@ func Oembed(c *http.Request) error { "author_url": artistURL, } - return c.JSON(data) + return r.JSON(data) } diff --git a/routes/newest.go b/routes/newest.go index e555dbd..8d5df9e 100644 --- a/routes/newest.go +++ b/routes/newest.go @@ -5,15 +5,15 @@ import ( "net/http" ) -func NewestPage(c *http.Request) error { - worktype := c.Query("type", "illust") +func NewestPage(w http.ResponseWriter, r CompatRequest) error { + worktype := r.Query("type", "illust") - r18 := c.Query("r18", "false") + r18 := r.Query("r18", "false") - works, err := core.GetNewestArtworks(c, worktype, r18) + works, err := core.GetNewestArtworks(r, worktype, r18) if err != nil { return err } - return Render(c, Data_newest{Items: works, Title: "Newest works"}) + return Render(w, r, Data_newest{Items: works, Title: "Newest works"}) } diff --git a/routes/novel.go b/routes/novel.go index 8b19634..fd0c4ab 100644 --- a/routes/novel.go +++ b/routes/novel.go @@ -10,31 +10,37 @@ import ( "net/http" ) -func NovelPage(c *http.Request) error { - id := c.Params("id") +func NovelPage(w http.ResponseWriter, r CompatRequest) error { + id := r.Params("id") if _, err := strconv.Atoi(id); err != nil { return fmt.Errorf("Invalid ID: %s", id) } - novel, err := core.GetNovelByID(c, id) + novel, err := core.GetNovelByID(r, id) if err != nil { return err } - related, err := core.GetNovelRelated(c, id) + related, err := core.GetNovelRelated(r, id) if err != nil { return err } - user, err := core.GetUserBasicInformation(c, novel.UserID) + user, err := core.GetUserBasicInformation(r, novel.UserID) if err != nil { return err } - fontType := session.GetCookie(c, session.Cookie_NovelFontType, "gothic") - viewMode := session.GetCookie(c, session.Cookie_NovelViewMode, strconv.Itoa(novel.Settings.ViewMode)) + fontType := session.GetCookie(r, session.Cookie_NovelFontType) + if fontType == "" { + fontType = "gothic" + } + viewMode := session.GetCookie(r, session.Cookie_NovelViewMode) + if viewMode == "" { + viewMode = strconv.Itoa(novel.Settings.ViewMode) + } // println("fontType", fontType) - return Render(c, Data_novel{Novel: novel, NovelRelated: related, User: user, Title: novel.Title, FontType: fontType, ViewMode: viewMode, Language: strings.ToLower(novel.Language)}) + return Render(w, r, Data_novel{Novel: novel, NovelRelated: related, User: user, Title: novel.Title, FontType: fontType, ViewMode: viewMode, Language: strings.ToLower(novel.Language)}) } diff --git a/routes/personal.go b/routes/personal.go index 39cda86..f824f98 100644 --- a/routes/personal.go +++ b/routes/personal.go @@ -9,55 +9,55 @@ import ( "codeberg.org/vnpower/pixivfe/v2/session" ) -func PromptUserToLoginPage(c *http.Request) error { - c.Status(http.StatusUnauthorized) - return Render(c, Data_unauthorized{}) +func PromptUserToLoginPage(w http.ResponseWriter, r CompatRequest) error { + r.Status(http.StatusUnauthorized) + return Render(w, r, Data_unauthorized{}) } -func LoginUserPage(c *http.Request) error { - token := session.GetPixivToken(c) +func LoginUserPage(w http.ResponseWriter, r CompatRequest) error { + token := session.GetPixivToken(r) if token == "" { - return PromptUserToLoginPage(c) + return PromptUserToLoginPage(r) } // The left part of the token is the member ID userId := strings.Split(token, "_") - c.Redirect("/users/" + userId[0]) + r.Redirect("/users/" + userId[0]) return nil } -func LoginBookmarkPage(c *http.Request) error { - token := session.GetPixivToken(c) +func LoginBookmarkPage(w http.ResponseWriter, r CompatRequest) error { + token := session.GetPixivToken(r) if token == "" { - return PromptUserToLoginPage(c) + return PromptUserToLoginPage(r) } // The left part of the token is the member ID userId := strings.Split(token, "_") - c.Redirect("/users/" + userId[0] + "/bookmarks#checkpoint") + r.Redirect("/users/" + userId[0] + "/bookmarks#checkpoint") return nil } -func FollowingWorksPage(c *http.Request) error { - if token := session.GetPixivToken(c); token == "" { - return PromptUserToLoginPage(c) +func FollowingWorksPage(w http.ResponseWriter, r CompatRequest) error { + if token := session.GetPixivToken(r); token == "" { + return PromptUserToLoginPage(r) } - mode := c.Query("mode", "all") - page := c.Query("page", "1") + mode := r.Query("mode", "all") + page := r.Query("page", "1") pageInt, err := strconv.Atoi(page) if err != nil { return err } - works, err := core.GetNewestFromFollowing(c, mode, page) + works, err := core.GetNewestFromFollowing(r, mode, page) if err != nil { return err } - return Render(c, Data_following{Title: "Following works", Mode: mode, Artworks: works, CurPage: page, Page: pageInt}) + return Render(w, r, Data_following{Title: "Following works", Mode: mode, Artworks: works, CurPage: page, Page: pageInt}) } diff --git a/routes/pixivision.go b/routes/pixivision.go index 64e56d4..0488985 100644 --- a/routes/pixivision.go +++ b/routes/pixivision.go @@ -7,33 +7,31 @@ import ( "net/http" ) -func PixivisionHomePage(c *http.Request) error { - // Note: don't process images here? +func PixivisionHomePage(w http.ResponseWriter, r CompatRequest) error { data, err := pixivision.GetHomepage() if err != nil { return err } for i := range data { - data[i].Thumbnail = session.ProxyImageUrlNoEscape(c, data[i].Thumbnail) + data[i].Thumbnail = session.ProxyImageUrlNoEscape(r, data[i].Thumbnail) } - return Render(c, Data_pixivision_index{Data: data}) + return Render(w, r, Data_pixivision_index{Data: data}) } -func PixivisionArticlePage(c *http.Request) error { - // Note: don't process images here? - id := c.Params("id") +func PixivisionArticlePage(w http.ResponseWriter, r CompatRequest) error { + id := r.Params("id") data, err := pixivision.GetArticle(id) if err != nil { return err } - data.Thumbnail = session.ProxyImageUrlNoEscape(c, data.Thumbnail) + data.Thumbnail = session.ProxyImageUrlNoEscape(r, data.Thumbnail) for i := range data.Items { - data.Items[i].Image = session.ProxyImageUrlNoEscape(c, data.Items[i].Image) - data.Items[i].Avatar = session.ProxyImageUrlNoEscape(c, data.Items[i].Avatar) + data.Items[i].Image = session.ProxyImageUrlNoEscape(r, data.Items[i].Image) + data.Items[i].Avatar = session.ProxyImageUrlNoEscape(r, data.Items[i].Avatar) } - return Render(c, Data_pixivision_article{Article: data}) + return Render(w, r, Data_pixivision_article{Article: data}) } diff --git a/routes/proxy.go b/routes/proxy.go index f3c5792..9ed62ea 100644 --- a/routes/proxy.go +++ b/routes/proxy.go @@ -6,78 +6,43 @@ import ( "net/http" ) -func SPximgProxy(c *http.Request) error { - URL := fmt.Sprintf("https://s.pximg.net/%s", c.Params("*")) - req, err := http.NewRequest("GET", URL, nil) - if err != nil { - return err - } - req = req.WithContext(c.Context()) - +func makeRequest(w http.ResponseWriter, req *http.Request) error { // Make the request resp, err := http.DefaultClient.Do(req) - if err != nil { return err } - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } + w.Header().Set("Content-Type", resp.Header.Get("Content-Type")) - c.Set("Content-Type", resp.Header.Get("Content-Type")) - - return c.Send([]byte(body)) + _, err = io.Copy(w, resp.Body) + return err } -func IPximgProxy(c *http.Request) error { - URL := fmt.Sprintf("https://i.pximg.net/%s", c.Params("*")) +func SPximgProxy(w http.ResponseWriter, r CompatRequest) error { + URL := fmt.Sprintf("https://s.pximg.net/%s", r.Params("*")) + req, err := http.NewRequest("GET", URL, nil) + if err != nil { + return err + } + return makeRequest(w, req.WithContext(r.Context())) +} + +func IPximgProxy(w http.ResponseWriter, r CompatRequest) error { + URL := fmt.Sprintf("https://i.pximg.net/%s", r.Params("*")) req, err := http.NewRequest("GET", URL, nil) if err != nil { return err } - req = req.WithContext(c.Context()) req.Header.Add("Referer", "https://www.pixiv.net/") - - // Make the request - resp, err := http.DefaultClient.Do(req) - - if err != nil { - return err - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - c.Set("Content-Type", resp.Header.Get("Content-Type")) - - return c.Send([]byte(body)) + return makeRequest(w, req.WithContext(r.Context())) } -func UgoiraProxy(c *http.Request) error { - URL := fmt.Sprintf("https://ugoira.com/api/mp4/%s", c.Params("*")) +func UgoiraProxy(w http.ResponseWriter, r CompatRequest) error { + URL := fmt.Sprintf("https://ugoira.com/api/mp4/%s", r.Params("*")) req, err := http.NewRequest("GET", URL, nil) if err != nil { return err } - req = req.WithContext(c.Context()) - - // Make the request - resp, err := http.DefaultClient.Do(req) - - if err != nil { - return err - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - c.Set("Content-Type", resp.Header.Get("Content-Type")) - - return c.Send([]byte(body)) + return makeRequest(w, req.WithContext(r.Context())) } diff --git a/routes/ranking.go b/routes/ranking.go index 3962e13..08b4b81 100644 --- a/routes/ranking.go +++ b/routes/ranking.go @@ -7,21 +7,21 @@ import ( "net/http" ) -func RankingPage(c *http.Request) error { - mode := c.Query("mode", "daily") - content := c.Query("content", "all") - date := c.Query("date", "") +func RankingPage(w http.ResponseWriter, r CompatRequest) error { + mode := r.Query("mode", "daily") + content := r.Query("content", "all") + date := r.Query("date", "") - page := c.Query("page", "1") + page := r.Query("page", "1") pageInt, err := strconv.Atoi(page) if err != nil { return err } - works, err := core.GetRanking(c, mode, content, date, page) + works, err := core.GetRanking(r, mode, content, date, page) if err != nil { return err } - return Render(c, Data_rank{Title: "Ranking", Page: pageInt, PageLimit: 10, Date: date, Data: works}) + return Render(w, r, Data_rank{Title: "Ranking", Page: pageInt, PageLimit: 10, Date: date, Data: works}) } diff --git a/routes/rankingCalendar.go b/routes/rankingCalendar.go index 1e6e236..d26d921 100644 --- a/routes/rankingCalendar.go +++ b/routes/rankingCalendar.go @@ -33,11 +33,11 @@ func parseDate(t time.Time) DateWrap { return d } -func RankingCalendarPicker(c *http.Request) error { - mode := c.FormValue("mode", "daily") - date := c.FormValue("date", "") +func RankingCalendarPicker(w http.ResponseWriter, r CompatRequest) error { + mode := r.FormValue("mode", "daily") + date := r.FormValue("date", "") - return c.RedirectToRoute("/rankingCalendar", fiber.Map{ + return r.RedirectToRoute("/rankingCalendar", fiber.Map{ "queries": map[string]string{ "mode": mode, "date": date, @@ -45,9 +45,9 @@ func RankingCalendarPicker(c *http.Request) error { }) } -func RankingCalendarPage(c *http.Request) error { - mode := c.Query("mode", "daily") - date := c.Query("date", "") +func RankingCalendarPage(w http.ResponseWriter, r CompatRequest) error { + mode := r.Query("mode", "daily") + date := r.Query("date", "") var year int var month int @@ -64,7 +64,7 @@ func RankingCalendarPage(c *http.Request) error { return err } } else { - now := c.Context().Time() + now := r.Context().Time() year = now.Year() month = int(now.Month()) } @@ -73,10 +73,10 @@ func RankingCalendarPage(c *http.Request) error { monthBefore := realDate.AddDate(0, -1, 0) monthAfter := realDate.AddDate(0, 1, 0) - render, err := core.GetRankingCalendar(c, mode, year, month) + render, err := core.GetRankingCalendar(r, mode, year, month) if err != nil { return err } - return Render(c, Data_rankingCalendar{Title: "Ranking calendar", Render: render, Mode: mode, Year: year, MonthBefore: parseDate(monthBefore), MonthAfter: parseDate(monthAfter), ThisMonth: parseDate(realDate)}) + return Render(w, r, Data_rankingCalendar{Title: "Ranking calendar", Render: render, Mode: mode, Year: year, MonthBefore: parseDate(monthBefore), MonthAfter: parseDate(monthAfter), ThisMonth: parseDate(realDate)}) } diff --git a/routes/render.go b/routes/render.go index db90e9e..328a081 100644 --- a/routes/render.go +++ b/routes/render.go @@ -33,10 +33,9 @@ func InitTemplatingEngine(DisableCache bool) { } } -func Render[T any](w http.ResponseWriter, r *http.Request, data T) error { - // Pass in values that we want to be available to all pages here - - r.Response.Header.Set("content-type", "text/html; charset=utf-8") +// render the template selected based on the name of type `T` +func Render[T any](w http.ResponseWriter, r CompatRequest, data T) error { + w.Header().Set("content-type", "text/html; charset=utf-8") return RenderInner(w, GetTemplatingVariables(r), data) } @@ -56,25 +55,12 @@ func RenderInner[T any](w io.Writer, variables jet.VarMap, data T) error { return template.Execute(w, variables, data) } -func GetTemplatingVariables(r *http.Request) jet.VarMap { +func GetTemplatingVariables(r CompatRequest) jet.VarMap { // Pass in values that we want to be available to all pages here token := session.GetPixivToken(r) - baseURL := (&url.URL{ - Scheme: r.URL.Scheme, - Opaque: r.URL.Opaque, - User: r.URL.User, - Host: r.URL.Host, - }).String() - originalURL := (&url.URL{ - Path: r.URL.Path, - RawPath: r.URL.RawPath, - OmitHost: r.URL.OmitHost, - ForceQuery: r.URL.ForceQuery, - RawQuery: r.URL.RawQuery, - Fragment: r.URL.Fragment, - RawFragment: r.URL.RawFragment, - }).String() - pageURL := r.URL.String() + baseURL := r.BaseURL() + originalURL := r.OriginalURL() + pageURL := r.PageURL() cookies := map[string]string{} for _, name := range session.AllCookieNames { diff --git a/routes/render_types.go b/routes/render_types.go index 2f3b7cb..1a09397 100644 --- a/routes/render_types.go +++ b/routes/render_types.go @@ -47,7 +47,7 @@ type Data_userAtom struct { } type Data_index struct { Title string - LoggedIn bool + LoggedIn bool Data core.LandingArtworks NoTokenData core.Ranking } diff --git a/routes/settings.go b/routes/settings.go index 43213ad..ba96357 100644 --- a/routes/settings.go +++ b/routes/settings.go @@ -17,13 +17,12 @@ import ( // todo: allow clear proxy // todo: allow clear all settings -func setToken(c *http.Request) error { - // Parse the value from the form - token := c.FormValue("token") +func setToken(w http.ResponseWriter, r CompatRequest) error { + token := r.FormValue("token") if token != "" { URL := httpc.GetNewestFromFollowingURL("all", "1") - _, err := httpc.UnwrapWebAPIRequest(c.Context(), URL, token) + _, err := httpc.UnwrapWebAPIRequest(r.Context(), URL, token) if err != nil { return errors.New("Cannot authorize with supplied token.") } @@ -34,7 +33,7 @@ func setToken(c *http.Request) error { if err != nil { return err } - req = req.WithContext(c.Context()) + req = req.WithContext(r.Context()) req.Header.Add("User-Agent", "Mozilla/5.0") req.AddCookie(&http.Cookie{ Name: "PHPSESSID", @@ -60,81 +59,80 @@ func setToken(c *http.Request) error { } // Set the token - session.SetCookie(c, session.Cookie_Token, token) - session.SetCookie(c, session.Cookie_CSRF, csrf) + session.SetCookie(w, session.Cookie_Token, token) + session.SetCookie(w, session.Cookie_CSRF, csrf) return nil } return errors.New("You submitted an empty/invalid form.") } -func setImageServer(c *http.Request) error { - // Parse the value from the form - token := c.FormValue("image-proxy") +func setImageServer(w http.ResponseWriter, r CompatRequest) error { + token := r.FormValue("image-proxy") if token != "" { - session.SetCookie(c, session.Cookie_ImageProxy, token) + session.SetCookie(w, session.Cookie_ImageProxy, token) } else { - session.ClearCookie(c, session.Cookie_ImageProxy) + session.ClearCookie(r, session.Cookie_ImageProxy) } return nil } -func setNovelFontType(c *http.Request) error { - fontType := c.FormValue("font-type") +func setNovelFontType(w http.ResponseWriter, r CompatRequest) error { + fontType := r.FormValue("font-type") if fontType != "" { - session.SetCookie(c, session.Cookie_NovelFontType, fontType) + session.SetCookie(w, session.Cookie_NovelFontType, fontType) } return nil } -func setNovelViewMode(c *http.Request) error { - viewMode := c.FormValue("view-mode") +func setNovelViewMode(w http.ResponseWriter, r CompatRequest) error { + viewMode := r.FormValue("view-mode") if viewMode != "" { - session.SetCookie(c, session.Cookie_NovelViewMode, viewMode) + session.SetCookie(w, session.Cookie_NovelViewMode, viewMode) } return nil } -func setThumbnailToNewTab(c *http.Request) error { - ttnt := c.FormValue("ttnt") +func setThumbnailToNewTab(w http.ResponseWriter, r CompatRequest) error { + ttnt := r.FormValue("ttnt") if ttnt == "_blank" || ttnt == "_self" { - session.SetCookie(c, session.Cookie_ThumbnailToNewTab, ttnt) + session.SetCookie(w, session.Cookie_ThumbnailToNewTab, ttnt) } return nil } -func setArtworkPreview(c *http.Request) error { - value := c.FormValue("app") +func setArtworkPreview(w http.ResponseWriter, r CompatRequest) error { + value := r.FormValue("app") if value == "cover" || value == "button" || value == "" { - session.SetCookie(c, session.Cookie_ArtworkPreview, value) + session.SetCookie(w, session.Cookie_ArtworkPreview, value) } return nil } -func setLogout(c *http.Request) error { - session.ClearCookie(c, session.Cookie_Token) - session.ClearCookie(c, session.Cookie_CSRF) +func setLogout(w http.ResponseWriter, r CompatRequest) error { + session.ClearCookie(r, session.Cookie_Token) + session.ClearCookie(r, session.Cookie_CSRF) return nil } -func setCookie(c *http.Request) error { - key := c.FormValue("key") - value := c.FormValue("value") +func setCookie(w http.ResponseWriter, r CompatRequest) error { + key := r.FormValue("key") + value := r.FormValue("value") for _, cookie_name := range session.AllCookieNames { if string(cookie_name) == key { - session.SetCookie(c, cookie_name, value) + session.SetCookie(w, cookie_name, value) return nil } } return fmt.Errorf("Invalid Cookie Name: %s", key) } -func setRawCookie(c *http.Request) error { - raw := c.FormValue("raw") +func setRawCookie(w http.ResponseWriter, r CompatRequest) error { + raw := r.FormValue("raw") lines := strings.Split(raw, "\n") for _, line := range lines { @@ -150,48 +148,46 @@ func setRawCookie(c *http.Request) error { continue } - session.SetCookie(c, name, value) + session.SetCookie(w, name, value) } return nil } -func resetAll(c *http.Request) error { - session.ClearAllCookies(c) +func resetAll(w http.ResponseWriter, r CompatRequest) error { + session.ClearAllCookies(w) return nil } -func SettingsPage(c *http.Request) error { - return Render(c, Data_settings{WorkingProxyList: config.GetWorkingProxies(), ProxyList: config.BuiltinProxyList}) +func SettingsPage(w http.ResponseWriter, r CompatRequest) error { + return Render(w, r, Data_settings{WorkingProxyList: config.GetWorkingProxies(), ProxyList: config.BuiltinProxyList}) } -func SettingsPost(c *http.Request) error { - // NOTE: VnPower: Future maintainers should leave this function alone. - - t := c.Params("type") - noredirect := c.FormValue("noredirect", "") == "" +func SettingsPost(w http.ResponseWriter, r CompatRequest) error { + t := r.Params("type") + noredirect := r.FormValue("noredirect", "") == "" var err error switch t { case "imageServer": - err = setImageServer(c) + err = setImageServer(r) case "token": - err = setToken(c) + err = setToken(r) case "logout": - err = setLogout(c) + err = setLogout(r) case "reset-all": - err = resetAll(c) + err = resetAll(r) case "novelFontType": - err = setNovelFontType(c) + err = setNovelFontType(r) case "thumbnailToNewTab": - err = setThumbnailToNewTab(c) + err = setThumbnailToNewTab(r) case "novelViewMode": - err = setNovelViewMode(c) + err = setNovelViewMode(r) case "artworkPreview": - err = setArtworkPreview(c) + err = setArtworkPreview(r) case "set-cookie": - err = setCookie(c) + err = setCookie(r) case "raw": - err = setRawCookie(c) + err = setRawCookie(r) default: err = errors.New("No such setting is available.") } @@ -204,5 +200,5 @@ func SettingsPost(c *http.Request) error { return nil } - return c.Redirect("/settings", http.StatusSeeOther) + return r.Redirect("/settings", http.StatusSeeOther) } diff --git a/routes/tag.go b/routes/tag.go index bdcecdc..9332be6 100644 --- a/routes/tag.go +++ b/routes/tag.go @@ -9,14 +9,14 @@ import ( "codeberg.org/vnpower/pixivfe/v2/utils" ) -func TagPage(c *http.Request) error { - param := c.Params("name", c.Query("name")) +func TagPage(w http.ResponseWriter, r CompatRequest) error { + param := r.Params("name", r.Query("name")) name, err := url.PathUnescape(param) if err != nil { return err } - page := c.Query("page", "1") + page := r.Query("page", "1") pageInt, err := strconv.Atoi(page) if err != nil { return err @@ -26,51 +26,50 @@ func TagPage(c *http.Request) error { // I made a struct type just to manage the queries queries := core.SearchPageSettings{ Name: name, - Category: c.Query("category", "artworks"), - Order: c.Query("order", "date_d"), - Mode: c.Query("mode", "safe"), - Ratio: c.Query("ratio", ""), - Wlt: c.Query("wlt", ""), - Wgt: c.Query("wgt", ""), - Hlt: c.Query("hlt", ""), - Hgt: c.Query("hgt", ""), - Tool: c.Query("tool", ""), - Scd: c.Query("scd", ""), - Ecd: c.Query("ecd", ""), + Category: r.Query("category", "artworks"), + Order: r.Query("order", "date_d"), + Mode: r.Query("mode", "safe"), + Ratio: r.Query("ratio", ""), + Wlt: r.Query("wlt", ""), + Wgt: r.Query("wgt", ""), + Hlt: r.Query("hlt", ""), + Hgt: r.Query("hgt", ""), + Tool: r.Query("tool", ""), + Scd: r.Query("scd", ""), + Ecd: r.Query("ecd", ""), Page: page, } - tag, err := core.GetTagData(c, name) + tag, err := core.GetTagData(r, name) if err != nil { return err } - result, err := core.GetSearch(c, queries) + result, err := core.GetSearch(r, queries) if err != nil { return err } urlc := utils.PartialURL{Path: "tags", Query: queries.ReturnMap()} - return Render(c, Data_tag{Title: "Results for " + name, Tag: tag, Data: *result, QueriesC: urlc, TrueTag: param, Page: pageInt}) + return Render(w, r, Data_tag{Title: "Results for " + name, Tag: tag, Data: *result, QueriesC: urlc, TrueTag: param, Page: pageInt}) } -func AdvancedTagPost(c *http.Request) error { - return c.RedirectToRoute("/tags", fiber.Map{ +func AdvancedTagPost(w http.ResponseWriter, r CompatRequest) error { + return r.RedirectToRoute("/tags", fiber.Map{ "queries": map[string]string{ - "name": c.Query("name", c.FormValue("name")), - "category": c.Query("category", "artworks"), - "order": c.Query("order", "date_d"), - "mode": c.Query("mode", "safe"), - "ratio": c.Query("ratio"), - "page": c.Query("page", "1"), - "wlt": c.Query("wlt", c.FormValue("wlt")), - "wgt": c.Query("wgt", c.FormValue("wgt")), - "hlt": c.Query("hlt", c.FormValue("hlt")), - "hgt": c.Query("hgt", c.FormValue("hgt")), - "tool": c.Query("tool", c.FormValue("tool")), - "scd": c.Query("scd", c.FormValue("scd")), - "ecd": c.Query("ecd", c.FormValue("ecd")), + "name": r.Query("name", r.FormValue("name")), + "category": r.Query("category", "artworks"), + "order": r.Query("order", "date_d"), + "mode": r.Query("mode", "safe"), + "ratio": r.Query("ratio"), + "page": r.Query("page", "1"), + "wlt": r.Query("wlt", r.FormValue("wlt")), + "wgt": r.Query("wgt", r.FormValue("wgt")), + "hlt": r.Query("hlt", r.FormValue("hlt")), + "hgt": r.Query("hgt", r.FormValue("hgt")), + "tool": r.Query("tool", r.FormValue("tool")), + "scd": r.Query("scd", r.FormValue("scd")), + "ecd": r.Query("ecd", r.FormValue("ecd")), }, }, http.StatusFound) - } diff --git a/routes/user.go b/routes/user.go index 41c0905..92a681a 100644 --- a/routes/user.go +++ b/routes/user.go @@ -16,24 +16,24 @@ type userPageData struct { page int } -func fetchData(c *http.Request, getTags bool) (userPageData, error) { - id := c.Params("id") +func fetchData(r *fiber.Ctx, getTags bool) (userPageData, error) { + id := r.Params("id") if _, err := strconv.Atoi(id); err != nil { return userPageData{}, err } - category := core.UserArtCategory(c.Params("category", string(core.UserArt_Any))) + category := core.UserArtCategory(r.Params("category", string(core.UserArt_Any))) err := category.Validate() if err != nil { return userPageData{}, err } - page_param := c.Query("page", "1") + page_param := r.Query("page", "1") page, err := strconv.Atoi(page_param) if err != nil { return userPageData{}, err } - user, err := core.GetUserArtwork(c, id, category, page, getTags) + user, err := core.GetUserArtwork(r, id, category, page, getTags) if err != nil { return userPageData{}, err } @@ -53,25 +53,25 @@ func fetchData(c *http.Request, getTags bool) (userPageData, error) { return userPageData{user, category, pageLimit, page}, nil } -func UserPage(c *http.Request) error { - data, err := fetchData(c, true) +func UserPage(w http.ResponseWriter, r CompatRequest) error { + data, err := fetchData(r, true) if err != nil { return err } - return Render(c, Data_user{Title: data.user.Name, User: data.user, Category: data.category, PageLimit: data.pageLimit, Page: data.page, MetaImage: data.user.BackgroundImage}) + return Render(w, r, Data_user{Title: data.user.Name, User: data.user, Category: data.category, PageLimit: data.pageLimit, Page: data.page, MetaImage: data.user.BackgroundImage}) } -func UserAtomFeed(c *http.Request) error { - data, err := fetchData(c, false) +func UserAtomFeed(w http.ResponseWriter, r CompatRequest) error { + data, err := fetchData(r, false) if err != nil { return err } - c.Context().SetContentType("application/atom+xml") + w.Header().Set("content-type", "application/atom+xml") - return Render(c, Data_userAtom{ - URL: string(c.Request().RequestURI()), + return Render(w, r, Data_userAtom{ + URL: r.RequestURI, Title: data.user.Name, User: data.user, Category: data.category, diff --git a/semgrep.yml b/semgrep.yml index fc3db00..5932bf6 100644 --- a/semgrep.yml +++ b/semgrep.yml @@ -102,7 +102,7 @@ rules: exclude: - "render_types.go" fix: | - Render(c, Data_$NAME{$...INSIDE}) + Render(w, r, Data_$NAME{$...INSIDE}) - id: rule-8 message: "c.Render" languages: [go] @@ -117,3 +117,16 @@ rules: paths: exclude: - "render.go" +- id: rule-9 + message: "still using *fiber.Ctx" + languages: [go] + severity: INFO + patterns: + - pattern: | + func $NAME(c *fiber.Ctx) error { + $...I + } + fix: | + func $NAME(w http.ResponseWriter, r *http.Request) error { + $...I + } diff --git a/session/aux.go b/session/aux.go index cfcb472..1d6f439 100644 --- a/session/aux.go +++ b/session/aux.go @@ -9,12 +9,12 @@ import ( config "codeberg.org/vnpower/pixivfe/v2/config" ) -func GetPixivToken(c *http.Request) string { - return GetCookie(c, Cookie_Token) +func GetPixivToken(r *http.Request) string { + return GetCookie(r, Cookie_Token) } -func GetImageProxy(c *http.Request) url.URL { - value := GetCookie(c, Cookie_ImageProxy) +func GetImageProxy(r *http.Request) url.URL { + value := GetCookie(r, Cookie_ImageProxy) if value == "" { // fall through to default case } else { @@ -28,29 +28,29 @@ func GetImageProxy(c *http.Request) url.URL { return config.GlobalServerConfig.ProxyServer } -func ProxyImageUrl(c *http.Request, s string) string { - proxyOrigin := GetImageProxyPrefix(c) +func ProxyImageUrl(r *http.Request, s string) string { + proxyOrigin := GetImageProxyPrefix(r) s = strings.ReplaceAll(s, `https:\/\/i.pximg.net`, proxyOrigin) // s = strings.ReplaceAll(s, `https:\/\/i.pximg.net`, "/proxy/i.pximg.net") s = strings.ReplaceAll(s, `https:\/\/s.pximg.net`, "/proxy/s.pximg.net") return s } -func ProxyImageUrlNoEscape(c *http.Request, s string) string { - proxyOrigin := GetImageProxyPrefix(c) +func ProxyImageUrlNoEscape(r *http.Request, s string) string { + proxyOrigin := GetImageProxyPrefix(r) s = strings.ReplaceAll(s, `https://i.pximg.net`, proxyOrigin) // s = strings.ReplaceAll(s, `https:\/\/i.pximg.net`, "/proxy/i.pximg.net") s = strings.ReplaceAll(s, `https://s.pximg.net`, "/proxy/s.pximg.net") return s } -func GetImageProxyOrigin(c *http.Request) string { - url := GetImageProxy(c) +func GetImageProxyOrigin(r *http.Request) string { + url := GetImageProxy(r) return urlAuthority(url) } -func GetImageProxyPrefix(c *http.Request) string { - url := GetImageProxy(c) +func GetImageProxyPrefix(r *http.Request) string { + url := GetImageProxy(r) return urlAuthority(url) + url.Path // note: not sure if url.EscapedPath() is useful here. go's standard library is trash at handling URL (:// should be part of the scheme) } diff --git a/session/cookie.go b/session/cookie.go index 27bdafb..55245ab 100644 --- a/session/cookie.go +++ b/session/cookie.go @@ -37,35 +37,31 @@ var AllCookieNames []CookieName = []CookieName{ Cookie_ShowArtAI, } -func GetCookie(c *http.Request, name CookieName, defaultValue ...string) string { - //return c.Cookies(string(name), defaultValue...) - if cookie, err := c.Cookie(string(name)); err != nil { - return cookie.Value +func GetCookie(r *http.Request, name CookieName) string { + cookie, err := r.Cookie(string(name)) + if err != nil { + return "" } - - // TODO: Hard-coded? - return defaultValue[0] + return cookie.Value } -func SetCookie(c *http.Request, name CookieName, value string) { - cookie := http.Cookie{ +func SetCookie(w http.ResponseWriter, name CookieName, value string) { + http.SetCookie(w, &http.Cookie{ Name: string(name), Value: value, Path: "/", // expires in 30 days from now - // Expires: c.Context().Time().Add(30 * (24 * time.Hour)), - Expires: time.Now().Add(30 * (24 * time.Hour)), + Expires: r.Context().Time().Add(30 * (24 * time.Hour)), HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, // bye-bye cross site forgery - } - c.AddCookie(&cookie) + }) } var CookieExpireDelete = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) -func ClearCookie(c *http.Request, name CookieName) { - cookie := http.Cookie{ +func ClearCookie(w http.ResponseWriter, name CookieName) { + http.SetCookie(w, &http.Cookie{ Name: string(name), Value: "", Path: "/", @@ -74,12 +70,11 @@ func ClearCookie(c *http.Request, name CookieName) { HttpOnly: true, Secure: true, SameSite: http.SameSiteStrictMode, - } - c.AddCookie(&cookie) + }) } -func ClearAllCookies(c *http.Request) { +func ClearAllCookies(w http.ResponseWriter) { for _, name := range AllCookieNames { - ClearCookie(c, name) + ClearCookie(w, name) } }