Initial tags support (#11)
This commit is contained in:
parent
5ba3b386a6
commit
07a202da8f
19
api/f.ts
19
api/f.ts
|
@ -1,19 +0,0 @@
|
||||||
export const fetchUserPosts = async (userID: string, sort: Sorting = 'newest'): Promise<Post[]> => {
|
|
||||||
/* eslint-disable max-len */
|
|
||||||
// https://api.imgur.com/3/account/mombotnumber5/submissions/0/newest?album_previews=1&client_id=${CLIENT_ID}
|
|
||||||
const response = await get(
|
|
||||||
``,
|
|
||||||
);
|
|
||||||
return JSON.parse(response.body).data;
|
|
||||||
/* eslint-enable max-len */
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchTagPosts = async (tagID: string, sort: Sorting = 'viral'): Promise<TagResult> => {
|
|
||||||
/* eslint-disable max-len */
|
|
||||||
// https://api.imgur.com/3/account/mombotnumber5/submissions/0/newest?album_previews=1&client_id=${CLIENT_ID}
|
|
||||||
const response = await get(
|
|
||||||
`https://api.imgur.com/3/gallery/t/${tagID.toLowerCase()}/${sort}/week/0?client_id=${CONFIG.imgur_client_id}`,
|
|
||||||
);
|
|
||||||
return JSON.parse(response.body).data;
|
|
||||||
/* eslint-enable max-len */
|
|
||||||
}
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"codeberg.org/video-prize-ranch/rimgo/types"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FetchTag(tag string, sort string, page string) (types.Tag, error) {
|
||||||
|
req, err := http.NewRequest("GET", "https://api.imgur.com/post/v1/posts/t/"+tag, nil)
|
||||||
|
if err != nil {
|
||||||
|
return types.Tag{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
q := req.URL.Query()
|
||||||
|
q.Add("client_id", viper.GetString("RIMGU_IMGUR_CLIENT_ID"))
|
||||||
|
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":
|
||||||
|
default:
|
||||||
|
q.Add("filter[window]", "week")
|
||||||
|
q.Add("sort", "-viral")
|
||||||
|
sort = "popular"
|
||||||
|
}
|
||||||
|
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return types.Tag{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return types.Tag{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := gjson.Parse(string(body))
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
posts := make([]types.Submission, 0)
|
||||||
|
data.Get("posts").ForEach(
|
||||||
|
func(key, value gjson.Result) bool {
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
posts = append(posts, types.Submission{
|
||||||
|
Id: value.Get("id").String(),
|
||||||
|
Title: value.Get("title").String(),
|
||||||
|
Link: strings.ReplaceAll(value.Get("url").String(), "https://imgur.com", ""),
|
||||||
|
Cover: types.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()
|
||||||
|
|
||||||
|
return types.Tag{
|
||||||
|
Tag: tag,
|
||||||
|
Display: data.Get("display").String(),
|
||||||
|
Sort: sort,
|
||||||
|
PostCount: data.Get("post_count").Int(),
|
||||||
|
Posts: posts,
|
||||||
|
Background: "/" + data.Get("background_id").String() + ".webp",
|
||||||
|
}, nil
|
||||||
|
}
|
2
main.go
2
main.go
|
@ -53,7 +53,7 @@ func main() {
|
||||||
app.Get("/:baseName.:extension", pages.HandleMedia)
|
app.Get("/:baseName.:extension", pages.HandleMedia)
|
||||||
app.Get("/:postID", pages.HandlePost)
|
app.Get("/:postID", pages.HandlePost)
|
||||||
app.Get("/a/:galleryID", pages.HandleGallery)
|
app.Get("/a/:galleryID", pages.HandleGallery)
|
||||||
//app.Get("/t/:tagID", pages.HandleAlbum)
|
app.Get("/t/:tag", pages.HandleTag)
|
||||||
app.Get("/user/:userID", pages.HandleUser)
|
app.Get("/user/:userID", pages.HandleUser)
|
||||||
app.Get("/r/:sub/:postID", pages.HandlePost)
|
app.Get("/r/:sub/:postID", pages.HandlePost)
|
||||||
app.Get("/user/:userID/cover", pages.HandleUserCover)
|
app.Get("/user/:userID/cover", pages.HandleUserCover)
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package pages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"codeberg.org/video-prize-ranch/rimgo/api"
|
||||||
|
"codeberg.org/video-prize-ranch/rimgo/utils"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleTag(c *fiber.Ctx) error {
|
||||||
|
utils.SetHeaders(c)
|
||||||
|
c.Set("Cache-Control", "public,max-age=604800")
|
||||||
|
c.Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline' 'self'; img-src 'self'; font-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 = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
displayPrevPage := true
|
||||||
|
if page == "1" {
|
||||||
|
displayPrevPage = false
|
||||||
|
}
|
||||||
|
|
||||||
|
tag, err := api.FetchTag(c.Params("tag"), c.Query("sort"), page)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Render("tag", fiber.Map{
|
||||||
|
"tag": tag,
|
||||||
|
"page": page,
|
||||||
|
"displayPrev": displayPrevPage,
|
||||||
|
"nextPage": pageNumber + 1,
|
||||||
|
"prevPage": pageNumber - 1,
|
||||||
|
})
|
||||||
|
}
|
|
@ -8,6 +8,10 @@ a > h2 {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2, p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #212121;
|
background-color: #212121;
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -33,6 +37,49 @@ main {
|
||||||
margin: 0 24vw;
|
margin: 0 24vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.posts {
|
||||||
|
margin-top: 1em;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
grid-auto-rows: 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post {
|
||||||
|
border-radius: 12px;
|
||||||
|
background-color: #3b3b3b;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
video:not(:fullscreen) {
|
||||||
|
object-fit: cover;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post__title {
|
||||||
|
margin: 0 6px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post__meta {
|
||||||
|
padding: 6px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post__meta .material-icons-outlined {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pageSelector {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
main {
|
||||||
|
margin: 0 12vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagMeta {
|
||||||
|
padding: 2em;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagMeta__info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagMeta__sort {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagMeta__sort a {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
|
@ -2,12 +2,8 @@ main {
|
||||||
margin: 0 12vw;
|
margin: 0 12vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2, p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.userMeta {
|
.userMeta {
|
||||||
padding: 2vw;
|
padding: 2em;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,46 +20,3 @@ h2, p {
|
||||||
.pfp {
|
.pfp {
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.posts {
|
|
||||||
margin-top: 1em;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
||||||
grid-auto-rows: 1fr;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post {
|
|
||||||
border-radius: 12px;
|
|
||||||
background-color: #3b3b3b;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
img,
|
|
||||||
video:not(:fullscreen) {
|
|
||||||
object-fit: cover;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post__title {
|
|
||||||
margin: 0 6px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post__meta {
|
|
||||||
padding: 6px;
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.post__meta .material-icons-outlined {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pageSelector {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
type Submission struct {
|
||||||
|
Id string
|
||||||
|
Title string
|
||||||
|
Link string
|
||||||
|
Cover Media
|
||||||
|
Points int64
|
||||||
|
Upvotes int64
|
||||||
|
Downvotes int64
|
||||||
|
Comments int64
|
||||||
|
Views int64
|
||||||
|
IsAlbum bool
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
type Tag struct {
|
||||||
|
Tag string
|
||||||
|
Display string
|
||||||
|
Sort string
|
||||||
|
PostCount int64
|
||||||
|
Posts []Submission
|
||||||
|
Background string
|
||||||
|
}
|
|
@ -9,16 +9,3 @@ type User struct {
|
||||||
Avatar string
|
Avatar string
|
||||||
CreatedAt string
|
CreatedAt string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Submission struct {
|
|
||||||
Id string
|
|
||||||
Title string
|
|
||||||
Link string
|
|
||||||
Cover Media
|
|
||||||
Points int64
|
|
||||||
Upvotes int64
|
|
||||||
Downvotes int64
|
|
||||||
Comments int64
|
|
||||||
Views int64
|
|
||||||
IsAlbum bool
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>{{tag.Display}} - rimgo</title>
|
||||||
|
|
||||||
|
{{> partials/head }}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/fonts/Material-Icons-Outlined.css" />
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css" />
|
||||||
|
<link rel="stylesheet" href="/static/css/tag.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{{> partials/header }}
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div class="tagMeta" style="background-image: url('{{tag.Background}}');">
|
||||||
|
<div class="tagMeta__info">
|
||||||
|
<h2>{{tag.Display}}</h2>
|
||||||
|
<p>{{tag.PostCount}} posts</p>
|
||||||
|
</div>
|
||||||
|
<div class="tagMeta__sort">
|
||||||
|
{{#equal tag.Sort "popular"}}
|
||||||
|
<a href="?sort=popular"><b>Popular</b></a>
|
||||||
|
<a href="?sort=newest">Newest</a>
|
||||||
|
<a href="?sort=best">Best</a>
|
||||||
|
{{/equal}}
|
||||||
|
{{#equal tag.Sort "newest"}}
|
||||||
|
<a href="?sort=popular">Popular</a>
|
||||||
|
<a href="?sort=newest"><b>Newest</b></a>
|
||||||
|
<a href="?sort=best">Best</a>
|
||||||
|
{{/equal}}
|
||||||
|
{{#equal tag.Sort "best"}}
|
||||||
|
<a href="?sort=popular">Popular</a>
|
||||||
|
<a href="?sort=newest">Newest</a>
|
||||||
|
<a href="?sort=best"><b>Best</b></a>
|
||||||
|
{{/equal}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="posts">
|
||||||
|
{{#each tag.Posts}}
|
||||||
|
{{> partials/post }}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pageSelector">
|
||||||
|
{{#if displayPrev}}
|
||||||
|
<a href="{{channel.RelUrl}}?page={{prevPage}}">Previous page</a>
|
||||||
|
{{/if}}
|
||||||
|
<a href="{{channel.RelUrl}}?page={{nextPage}}">Next page</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{{> partials/footer }}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Loading…
Reference in New Issue