Initial tags support (#11)

This commit is contained in:
video-prize-ranch 2022-02-18 16:56:56 -05:00
parent 5ba3b386a6
commit 07a202da8f
No known key found for this signature in database
GPG Key ID: D8EAA4C5B12A7281
11 changed files with 296 additions and 82 deletions

View File

@ -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 */
}

93
api/tag.go Normal file
View File

@ -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
}

View File

@ -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)

43
pages/tag.go Normal file
View File

@ -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,
})
}

View File

@ -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;

27
static/css/tag.css Normal file
View File

@ -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;
}

View File

@ -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;
}

14
types/Submission.go Normal file
View File

@ -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
}

10
types/Tag.go Normal file
View File

@ -0,0 +1,10 @@
package types
type Tag struct {
Tag string
Display string
Sort string
PostCount int64
Posts []Submission
Background string
}

View File

@ -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
}

59
views/tag.hbs Normal file
View File

@ -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>