diff --git a/api/trending.go b/api/trending.go new file mode 100644 index 0000000..b69a345 --- /dev/null +++ b/api/trending.go @@ -0,0 +1,107 @@ +package api + +import ( + "fmt" + "io" + "net/http" + "strings" + "sync" + + "codeberg.org/rimgo/rimgo/utils" + "github.com/patrickmn/go-cache" + "github.com/tidwall/gjson" +) + +func (client *Client) FetchTrending(section, sort, page string) ([]Submission, error) { + cacheData, found := client.Cache.Get(fmt.Sprintf("trending-%s-%s-%s", section, sort, page)) + if found { + return cacheData.([]Submission), nil + } + + req, err := http.NewRequest("GET", "https://api.imgur.com/post/v1/posts", nil) + if err != nil { + return []Submission{}, err + } + utils.SetReqHeaders(req) + + q := req.URL.Query() + q.Add("client_id", client.ClientID) + q.Add("include", "cover") + q.Add("page", page) + + switch sort { + case "newest": + q.Add("filter[window]", "week") + q.Add("sort", "-time") + case "best": + q.Add("filter[window]", "all") + q.Add("sort", "-top") + case "popular": + fallthrough + default: + q.Add("filter[window]", "week") + q.Add("sort", "-viral") + sort = "popular" + } + switch section { + case "hot": + q.Add("filter[section]", "eq:hot") + case "new": + q.Add("filter[section]", "eq:new") + case "top": + q.Add("filter[section]", "eq:top") + q.Add("filter[window]", "day") + default: + q.Add("filter[section]", "eq:hot") + section = "hot" + } + + req.URL.RawQuery = q.Encode() + + res, err := http.DefaultClient.Do(req) + if err != nil { + return []Submission{}, err + } + + body, err := io.ReadAll(res.Body) + if err != nil { + return []Submission{}, err + } + + data := gjson.Parse(string(body)) + + wg := sync.WaitGroup{} + posts := make([]Submission, 0) + data.ForEach( + func(key, value gjson.Result) bool { + wg.Add(1) + + go func() { + defer wg.Done() + posts = append(posts, Submission{ + Id: value.Get("id").String(), + Title: value.Get("title").String(), + Link: strings.ReplaceAll(value.Get("url").String(), "https://imgur.com", ""), + Cover: Media{ + Id: value.Get("cover_id").String(), + Type: value.Get("cover.type").String(), + Url: strings.ReplaceAll(value.Get("cover.url").String(), "https://i.imgur.com", ""), + }, + Points: value.Get("point_count").Int(), + Upvotes: value.Get("upvote_count").Int(), + Downvotes: value.Get("downvote_count").Int(), + Comments: value.Get("comment_count").Int(), + Views: value.Get("view_count").Int(), + IsAlbum: value.Get("is_album").Bool(), + }) + }() + + return true + }, + ) + + wg.Wait() + + client.Cache.Set(fmt.Sprintf("trending-%s-%s-%s", section, sort, page), posts, cache.DefaultExpiration) + return posts, nil +} diff --git a/main.go b/main.go index ce0572f..0a1cd52 100644 --- a/main.go +++ b/main.go @@ -24,7 +24,7 @@ func main() { envPath := flag.String("c", ".env", "Path to env file") godotenv.Load(*envPath) utils.LoadConfig() - + pages.InitializeApiClient() views := http.FS(views.GetFiles()) @@ -32,7 +32,7 @@ func main() { views = http.Dir("./views") } engine := handlebars.NewFileSystem(views, ".hbs") - + engine.AddFunc("noteq", func(a interface{}, b interface{}, options *raymond.Options) interface{} { if raymond.Str(a) != raymond.Str(b) { return options.Fn() @@ -69,11 +69,11 @@ func main() { fmt.Println(e) }, })) - + if os.Getenv("ENV") == "dev" { app.Use("/static", filesystem.New(filesystem.Config{ MaxAge: 2592000, - Root: http.Dir("./static"), + Root: http.Dir("./static"), })) app.Get("/errors/429", func(c *fiber.Ctx) error { return c.Render("errors/429", nil) @@ -91,11 +91,11 @@ func main() { Root: http.FS(static.GetFiles()), })) app.Use(cache.New(cache.Config{ - Expiration: 30 * time.Minute, - MaxBytes: 25000000, + Expiration: 30 * time.Minute, + MaxBytes: 25000000, KeyGenerator: func(c *fiber.Ctx) string { - return c.OriginalURL() - }, + return c.OriginalURL() + }, CacheControl: true, StoreResponseHeaders: true, })) @@ -116,6 +116,7 @@ func main() { app.Get("/about", pages.HandleAbout) app.Get("/privacy", pages.HandlePrivacy) app.Get("/search", pages.HandleSearch) + app.Get("/trending", pages.HandleTrending) app.Get("/a/:postID", pages.HandlePost) app.Get("/a/:postID/embed", pages.HandleEmbed) app.Get("/t/:tag", pages.HandleTag) diff --git a/pages/trending.go b/pages/trending.go new file mode 100644 index 0000000..89dd9ab --- /dev/null +++ b/pages/trending.go @@ -0,0 +1,58 @@ +package pages + +import ( + "strconv" + + "codeberg.org/rimgo/rimgo/utils" + "github.com/gofiber/fiber/v2" +) + +func HandleTrending(c *fiber.Ctx) error { + utils.SetHeaders(c) + c.Set("X-Frame-Options", "DENY") + c.Set("Cache-Control", "public,max-age=604800") + c.Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'; style-src 'unsafe-inline' 'self'; media-src 'self'; img-src 'self'; manifest-src 'self'; block-all-mixed-content") + + page := "1" + if c.Query("page") != "" { + page = c.Query("page") + } + + pageNumber, err := strconv.Atoi(c.Query("page")) + if err != nil { + pageNumber = 1 + } + + section := c.Query("section") + switch section { + case "hot", "new", "top": + default: + section = "hot" + } + sort := c.Query("sort") + switch sort { + case "newest", "best", "popular": + default: + sort = "popular" + } + + displayPrevPage := true + if page == "1" { + displayPrevPage = false + } + + results, err := ApiClient.FetchTrending(section, sort, page) + if err != nil { + return err + } + + return c.Render("trending", fiber.Map{ + "results": results, + "section": section, + "sort": sort, + "page": pageNumber, + "displayPrev": displayPrevPage, + "nextPage": pageNumber + 1, + "prevPage": pageNumber - 1, + }) +} diff --git a/static/icons/PhArrowUpRight.svg b/static/icons/PhArrowUpRight.svg new file mode 100644 index 0000000..4d98f58 --- /dev/null +++ b/static/icons/PhArrowUpRight.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/views/frontpage.hbs b/views/frontpage.hbs index 11b3b97..6101526 100644 --- a/views/frontpage.hbs +++ b/views/frontpage.hbs @@ -13,6 +13,7 @@ The fast, private image viewer for Imgur. {{> partials/searchBar }} + Or see what's trending diff --git a/views/trending.hbs b/views/trending.hbs new file mode 100644 index 0000000..f460175 --- /dev/null +++ b/views/trending.hbs @@ -0,0 +1,79 @@ + + + + + Trending - rimgo + + {{> partials/head }} + + + + {{> partials/nav }} + + + {{> partials/searchBar }} + + + + + Trending + + + + {{#equal section "hot"}} + Hot + New + Top + {{/equal}} + {{#equal section "new"}} + Hot + New + Top + {{/equal}} + {{#equal section "top"}} + Hot + New + Top + {{/equal}} + + + + {{#equal sort "popular"}} + Popular + Newest + Best + {{/equal}} + {{#equal sort "newest"}} + Popular + Newest + Best + {{/equal}} + {{#equal sort "best"}} + Popular + Newest + Best + {{/equal}} + + + + + + + {{#each results}} + {{> partials/post }} + {{/each}} + + + + {{#if displayPrev}} + Previous page + {{/if}} + Page {{page}} + Next page + + + + {{> partials/footer }} + + + \ No newline at end of file
Page {{page}}