next button for tagged posts (#169)
No previous button because that would be annoying to implement serverside with pagination etc. Closes #115 Fixed conflict with #154, #155, #156 Co-authored-by: video-prize-ranch <cb.8a3w5@simplelogin.co> Reviewed-on: https://codeberg.org/rimgo/rimgo/pulls/169 Reviewed-by: video-prize-ranch <video-prize-ranch@noreply.codeberg.org> Co-authored-by: orangix <orangix@noreply.codeberg.org> Co-committed-by: orangix <orangix@noreply.codeberg.org>
This commit is contained in:
parent
7433265991
commit
927ea20fad
64
api/tag.go
64
api/tag.go
|
@ -3,9 +3,9 @@ package api
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/patrickmn/go-cache"
|
"github.com/patrickmn/go-cache"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,9 @@ type Tag struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) FetchTag(tag string, sort string, page string) (Tag, error) {
|
func (client *Client) FetchTag(tag string, sort string, page string) (Tag, error) {
|
||||||
|
// Dots are automatically removed on Imgur, so more cache hits
|
||||||
|
tag = strings.ReplaceAll(tag, ".", "")
|
||||||
|
|
||||||
cacheData, found := client.Cache.Get(tag + sort + page + "-tag")
|
cacheData, found := client.Cache.Get(tag + sort + page + "-tag")
|
||||||
if found {
|
if found {
|
||||||
return cacheData.(Tag), nil
|
return cacheData.(Tag), nil
|
||||||
|
@ -64,47 +67,44 @@ func (client *Client) FetchTag(tag string, sort string, page string) (Tag, error
|
||||||
|
|
||||||
data := gjson.Parse(string(body))
|
data := gjson.Parse(string(body))
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
|
||||||
posts := make([]Submission, 0)
|
posts := make([]Submission, 0)
|
||||||
data.Get("posts").ForEach(
|
data.Get("posts").ForEach(
|
||||||
func(key, value gjson.Result) bool {
|
func(key, value gjson.Result) bool {
|
||||||
wg.Add(1)
|
url, _ := url.Parse(strings.ReplaceAll(value.Get("url").String(), "https://imgur.com", ""))
|
||||||
|
q := url.Query()
|
||||||
|
q.Add("tag", tag+"."+sort+"."+page+"."+key.String())
|
||||||
|
url.RawQuery = q.Encode()
|
||||||
|
|
||||||
go func() {
|
posts = append(posts, Submission{
|
||||||
defer wg.Done()
|
Id: value.Get("id").String(),
|
||||||
posts = append(posts, Submission{
|
Title: value.Get("title").String(),
|
||||||
Id: value.Get("id").String(),
|
Link: url.String(),
|
||||||
Title: value.Get("title").String(),
|
Cover: Media{
|
||||||
Link: strings.ReplaceAll(value.Get("url").String(), "https://imgur.com", ""),
|
Id: value.Get("cover_id").String(),
|
||||||
Cover: Media{
|
Type: value.Get("cover.type").String(),
|
||||||
Id: value.Get("cover_id").String(),
|
Url: strings.ReplaceAll(value.Get("cover.url").String(), "https://i.imgur.com", ""),
|
||||||
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(),
|
||||||
Points: value.Get("point_count").Int(),
|
Downvotes: value.Get("downvote_count").Int(),
|
||||||
Upvotes: value.Get("upvote_count").Int(),
|
Comments: value.Get("comment_count").Int(),
|
||||||
Downvotes: value.Get("downvote_count").Int(),
|
Views: value.Get("view_count").Int(),
|
||||||
Comments: value.Get("comment_count").Int(),
|
IsAlbum: value.Get("is_album").Bool(),
|
||||||
Views: value.Get("view_count").Int(),
|
})
|
||||||
IsAlbum: value.Get("is_album").Bool(),
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
tagData := Tag{
|
tagData := Tag{
|
||||||
Tag: tag,
|
Tag: tag,
|
||||||
Display: data.Get("display").String(),
|
Display: data.Get("display").String(),
|
||||||
Sort: sort,
|
Sort: sort,
|
||||||
PostCount: data.Get("post_count").Int(),
|
PostCount: data.Get("post_count").Int(),
|
||||||
Posts: posts,
|
Posts: posts,
|
||||||
Background: "/" + data.Get("background_id").String() + ".webp",
|
Background: "/" + data.Get("background_id").String() + ".webp",
|
||||||
}
|
}
|
||||||
|
|
||||||
client.Cache.Set(tag + sort + page + "-tag", tagData, cache.DefaultExpiration)
|
client.Cache.Set(tag+sort+page+"-tag", tagData, 4*cache.DefaultExpiration)
|
||||||
return tagData, nil
|
return tagData, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package pages
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"codeberg.org/rimgo/rimgo/api"
|
"codeberg.org/rimgo/rimgo/api"
|
||||||
|
@ -10,6 +11,27 @@ import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Cursed function
|
||||||
|
func nextInTag(client *api.Client, tagname, sort, page, I string) string {
|
||||||
|
i, err := strconv.Atoi(I)
|
||||||
|
if err != nil || i < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
tag, err := client.FetchTag(tagname, sort, page)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if i >= len(tag.Posts)-1 {
|
||||||
|
pageNumber, _ := strconv.Atoi(page)
|
||||||
|
tagn, err := client.FetchTag(tagname, sort, strconv.Itoa(pageNumber+1))
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return tagn.Posts[0].Link
|
||||||
|
}
|
||||||
|
return tag.Posts[i+1].Link
|
||||||
|
}
|
||||||
|
|
||||||
func HandlePost(c *fiber.Ctx) error {
|
func HandlePost(c *fiber.Ctx) error {
|
||||||
utils.SetHeaders(c)
|
utils.SetHeaders(c)
|
||||||
c.Set("X-Frame-Options", "DENY")
|
c.Set("X-Frame-Options", "DENY")
|
||||||
|
@ -56,8 +78,16 @@ func HandlePost(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
c.Set("Content-Security-Policy", csp)
|
c.Set("Content-Security-Policy", csp)
|
||||||
|
|
||||||
|
var next string
|
||||||
|
tagParam := strings.Split(c.Query("tag"), ".")
|
||||||
|
if len(tagParam) == 4 {
|
||||||
|
tag, sort, page, index := tagParam[0], tagParam[1], tagParam[2], tagParam[3]
|
||||||
|
next = nextInTag(ApiClient, tag, sort, page, index)
|
||||||
|
}
|
||||||
|
|
||||||
return c.Render("post", fiber.Map{
|
return c.Render("post", fiber.Map{
|
||||||
"post": post,
|
"post": post,
|
||||||
|
"next": next,
|
||||||
"comments": comments,
|
"comments": comments,
|
||||||
"nonce": nonce,
|
"nonce": nonce,
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<head>
|
<head>
|
||||||
<title>
|
<title>
|
||||||
{{#if post.Title}}
|
{{#if post.Title}}
|
||||||
{{post.Title}} -
|
{{post.Title}} -
|
||||||
{{/if}}
|
{{/if}}
|
||||||
rimgo
|
rimgo
|
||||||
</title>
|
</title>
|
||||||
|
@ -23,33 +23,40 @@
|
||||||
<h1 class="text-3xl font-bold">{{post.Title}}</h1>
|
<h1 class="text-3xl font-bold">{{post.Title}}</h1>
|
||||||
<p>{{post.CreatedAt}}</p>
|
<p>{{post.CreatedAt}}</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div class="flex flex-col gap-2 md:flex-row md:gap-4 md:items-center my-4">
|
<div class="flex flex-col sm:flex-row my-4 w-full justify-between">
|
||||||
{{#if post.User.Username}}
|
<div class="flex flex-col gap-2 md:flex-row md:gap-4 md:items-center">
|
||||||
<a href="/user/{{post.User.Username}}" class="flex gap-2 items-center">
|
{{#if post.User.Username}}
|
||||||
<img src="{{post.User.Avatar}}" class="rounded-full" width="36" height="36" />
|
<a href="/user/{{post.User.Username}}" class="flex gap-2 items-center">
|
||||||
<p>
|
<img src="{{post.User.Avatar}}" class="rounded-full" width="36" height="36" />
|
||||||
<b>{{post.User.Username}}</b>
|
<p>
|
||||||
</p>
|
<b>{{post.User.Username}}</b>
|
||||||
</a>
|
</p>
|
||||||
{{/if}}
|
</a>
|
||||||
<div class="flex gap-2 items-center">
|
|
||||||
<div class="flex flex-center gap-2">
|
|
||||||
<img class="icon invert" src="/static/icons/PhEye.svg" alt="Views" width="24px" height="24px">
|
|
||||||
<p>{{post.Views}}</p>
|
|
||||||
</div>
|
|
||||||
{{#if post.SharedWithCommunity}}
|
|
||||||
<div class="flex flex-center gap-2">
|
|
||||||
<img class="icon invert" src="/static/icons/PhArrowFatUp.svg" alt="Likes" width="24px" height="24px">
|
|
||||||
<p>{{post.Upvotes}}</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-center gap-2">
|
|
||||||
<img class="icon invert" src="/static/icons/PhArrowFatDown.svg" alt="Dislikes" width="24px" height="24px">
|
|
||||||
<p>{{post.Downvotes}}</p>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
<div class="flex gap-2 items-center">
|
||||||
|
<div class="flex flex-center gap-2">
|
||||||
|
<img class="icon invert" src="/static/icons/PhEye.svg" alt="Views" width="24px" height="24px">
|
||||||
|
<p>{{post.Views}}</p>
|
||||||
|
</div>
|
||||||
|
{{#if post.SharedWithCommunity}}
|
||||||
|
<div class="flex flex-center gap-2">
|
||||||
|
<img class="icon invert" src="/static/icons/PhArrowFatUp.svg" alt="Likes" width="24px" height="24px">
|
||||||
|
<p>{{post.Upvotes}}</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-center gap-2">
|
||||||
|
<img class="icon invert" src="/static/icons/PhArrowFatDown.svg" alt="Dislikes" width="24px" height="24px">
|
||||||
|
<p>{{post.Downvotes}}</p>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{#noteq next ""}}
|
||||||
|
<a href="{{next}}" class="self-end">
|
||||||
|
<button class="p-2 rounded-lg bg-slate-600">Next ></button>
|
||||||
|
</a>
|
||||||
|
{{/noteq}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-center flex-col break-words">
|
<div class="flex flex-center flex-col break-words">
|
||||||
|
@ -70,7 +77,7 @@
|
||||||
{{#if this.Description}}
|
{{#if this.Description}}
|
||||||
<p>{{{this.Description}}}</p>
|
<p>{{{this.Description}}}</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if post.tags}}
|
{{#if post.tags}}
|
||||||
|
@ -78,7 +85,7 @@
|
||||||
<style nonce="{{nonce}}">
|
<style nonce="{{nonce}}">
|
||||||
{{#each post.tags}}
|
{{#each post.tags}}
|
||||||
.{{this.BackgroundId}} { background-image: url('{{this.Background}}') }
|
.{{this.BackgroundId}} { background-image: url('{{this.Background}}') }
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</style>
|
</style>
|
||||||
{{#each post.tags}}
|
{{#each post.tags}}
|
||||||
<a href="/t/{{this.Tag}}">
|
<a href="/t/{{this.Tag}}">
|
||||||
|
@ -101,7 +108,8 @@
|
||||||
{{#if comments}}
|
{{#if comments}}
|
||||||
<div>
|
<div>
|
||||||
<input id="comments__expandBtn" type="checkbox" checked>
|
<input id="comments__expandBtn" type="checkbox" checked>
|
||||||
<label class="comments__expandBtn__label my-2 py-4 border-solid border-t-2 border-slate-400" for="comments__expandBtn">
|
<label class="comments__expandBtn__label my-2 py-4 border-solid border-t-2 border-slate-400"
|
||||||
|
for="comments__expandBtn">
|
||||||
<h3 class="text-xl font-bold">Comments ({{post.Comments}})</h3>
|
<h3 class="text-xl font-bold">Comments ({{post.Comments}})</h3>
|
||||||
<span class="text-xl font-bold"></span>
|
<span class="text-xl font-bold"></span>
|
||||||
</label>
|
</label>
|
||||||
|
|
Loading…
Reference in New Issue