user favourites

This commit is contained in:
lost+skunk 2024-08-14 19:18:06 +03:00
parent 513543cc7a
commit 2f8c35ba32
9 changed files with 147 additions and 121 deletions

View File

@ -2,6 +2,6 @@
|:------:|:-------:|:-:|:-:|:--:|:--------:|:--------------:|:-----:| |:------:|:-------:|:-:|:-:|:--:|:--------:|:--------------:|:-----:|
|[skunky.ebloid.ru](https://skunky.ebloid.ru/art)|[Yes](http://[201:eba5:d1fc:bf7b:cfcb:a811:4b8b:7ea3]/art)|No|No| No | No | No | Russia | |[skunky.ebloid.ru](https://skunky.ebloid.ru/art)|[Yes](http://[201:eba5:d1fc:bf7b:cfcb:a811:4b8b:7ea3]/art)|No|No| No | No | No | Russia |
|[clovius.club](https://skunky.clovius.club)|No|No|No| Yes | Yes | No | Sweden | |[clovius.club](https://skunky.clovius.club)|No|No|No| Yes | Yes | No | Sweden |
|[bloat.cat](https://skunky.bloat.cat)|No|No|No| Yes | Yes | No | Romania | |[bloat.cat](https://skunky.bloat.cat)|No|No|No| Yes | Yes | No | Germany |
|[frontendfriendly.xyz](https://skunkyart.frontendfriendly.xyz)|No|No|No| Yes | Yes | No | Finland | |[frontendfriendly.xyz](https://skunkyart.frontendfriendly.xyz)|No|No|No| Yes | Yes | No | Finland |
|[lumaeris.com](https://skunkyart.lumaeris.com)|No|No|No| Yes | Yes | No | US | |[lumaeris.com](https://skunkyart.lumaeris.com)|No|No|No| Yes | Yes | No | US |

View File

@ -6,7 +6,7 @@
* ~~Исправить баг с навигацией по страницам~~ ✔️ * ~~Исправить баг с навигацией по страницам~~ ✔️
* Сделать нормальное отображение ошибок * Сделать нормальное отображение ошибок
* ~~Сделать единицы в конфиге более понятными~~ ✔️ * ~~Сделать единицы в конфиге более понятными~~ ✔️
* Добавить просмотр понравившихся артов пользователю * ~~Добавить просмотр понравившихся артов пользователю~~ ✔️
* Добавить возможность включить темплейты в бинарник [P] * Добавить возможность включить темплейты в бинарник [P]
* ~~Реализовать миниатюры и оптимизировать CSS под маленькие экраны~~ ✔️ * ~~Реализовать миниатюры и оптимизировать CSS под маленькие экраны~~ ✔️
* Написать Makefile и скрипт для автоматического развёртывания инстанса * Написать Makefile и скрипт для автоматического развёртывания инстанса

View File

@ -99,34 +99,36 @@ func (s skunkyart) DownloadAndSendMedia(subdomain, path string) {
func InitCacheSystem() { func InitCacheSystem() {
c := &CFG.Cache c := &CFG.Cache
os.Mkdir(c.Path, 0700)
for { for {
dir, e := os.Open(c.Path) dir, err := os.ReadDir(c.Path)
try(e) if err != nil {
stat, e := dir.Stat() if os.IsNotExist(err) {
try(e) os.Mkdir(c.Path, 0700)
continue
}
println(err.Error())
}
for _, file := range dir {
fileName := c.Path + "/" + file.Name()
fileInfo, err := file.Info()
try(err)
dirnames, e := dir.Readdirnames(-1)
try(e)
for _, a := range dirnames {
a = c.Path + "/" + a
if c.Lifetime != "" { if c.Lifetime != "" {
now := time.Now().UnixMilli() now := time.Now().UnixMilli()
f, _ := os.Stat(a) stat := fileInfo.Sys().(*syscall.Stat_t)
stat := f.Sys().(*syscall.Stat_t)
time := statTime(stat) time := statTime(stat)
if time+lifetimeParsed <= now { if time+lifetimeParsed <= now {
try(os.RemoveAll(a)) try(os.RemoveAll(fileName))
} }
} }
if c.MaxSize != 0 && stat.Size() > c.MaxSize { if c.MaxSize != 0 && fileInfo.Size() > c.MaxSize {
try(os.RemoveAll(a)) try(os.RemoveAll(fileName))
} }
} }
dir.Close()
time.Sleep(time.Second * time.Duration(c.UpdateInterval)) time.Sleep(time.Second * time.Duration(c.UpdateInterval))
} }
} }

View File

@ -16,6 +16,8 @@ import (
) )
/* INTERNAL */ /* INTERNAL */
var wr = io.WriteString
func exit(msg string, code int) { func exit(msg string, code int) {
println(msg) println(msg)
os.Exit(code) os.Exit(code)
@ -50,6 +52,63 @@ func RefreshInstances() {
} }
// some crap for frontend // some crap for frontend
type skunkyart struct {
Writer http.ResponseWriter
Args url.Values
Page int
Type rune
Atom bool
BasePath, Endpoint string
Query, QueryRaw string
Templates struct {
About struct {
Proxy bool
Nsfw bool
Instances []settings
}
SomeList string
DDStrips string
Deviation struct {
Post devianter.Post
Related string
StringTime string
Tags string
Comments string
}
GroupUser struct {
GR devianter.GRuser
Admins string
Group bool
CreationDate string
About struct {
A devianter.About
DescriptionFormatted string
Interests, Social string
Comments string
BG string
BGMeta devianter.Deviation
}
Gallery struct {
Folders string
Pages int
List string
}
}
Search struct {
Content devianter.Search
List string
}
}
}
func (s skunkyart) ExecuteTemplate(file, dir string, data any) { func (s skunkyart) ExecuteTemplate(file, dir string, data any) {
var buf strings.Builder var buf strings.Builder
tmp := template.New(file) tmp := template.New(file)

View File

@ -2,9 +2,6 @@ package app
import ( import (
"encoding/json" "encoding/json"
"io"
"net/http"
"net/url"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -14,65 +11,6 @@ import (
"golang.org/x/net/html" "golang.org/x/net/html"
) )
var wr = io.WriteString
type skunkyart struct {
Writer http.ResponseWriter
Args url.Values
Page int
Type rune
Atom bool
BasePath, Endpoint string
Query, QueryRaw string
Templates struct {
About struct {
Proxy bool
Nsfw bool
Instances []settings
}
SomeList string
DDStrips string
Deviation struct {
Post devianter.Post
Related string
StringTime string
Tags string
Comments string
}
GroupUser struct {
GR devianter.GRuser
Admins string
Group bool
CreationDate string
About struct {
A devianter.About
DescriptionFormatted string
Interests, Social string
Comments string
BG string
BGMeta devianter.Deviation
}
Gallery struct {
Folders string
Pages int
List string
}
}
Search struct {
Content devianter.Search
List string
}
}
}
func (s skunkyart) GRUser() { func (s skunkyart) GRUser() {
if len(s.Query) < 1 { if len(s.Query) < 1 {
s.ReturnHTTPError(400) s.ReturnHTTPError(400)
@ -82,7 +20,7 @@ func (s skunkyart) GRUser() {
var g devianter.Group var g devianter.Group
g.Name = s.Query g.Name = s.Query
var err error var err error
s.Templates.GroupUser.GR, err = g.GetGroup() s.Templates.GroupUser.GR, err = g.Get()
try(err) try(err)
group := &s.Templates.GroupUser group := &s.Templates.GroupUser
@ -146,25 +84,38 @@ func (s skunkyart) GRUser() {
} }
} }
case 'g': case 'g', 'f':
var all bool
var content devianter.Group
folderid, _ := strconv.Atoi(s.Args.Get("folder")) folderid, _ := strconv.Atoi(s.Args.Get("folder"))
if a := s.Args.Get("all"); a == "true" {
all = true
}
if s.Page == 0 { if s.Page == 0 {
s.Page++ s.Page++
} }
gallery, err := g.GetGallery(s.Page, folderid) if s.Type == 'f' {
content = g.Favourites(s.Page, all, folderid)
} else {
content, err = g.Gallery(s.Page, folderid)
try(err) try(err)
}
if folderid > 0 { if folderid > 0 || (s.Type == 'f' && all) {
group.Gallery.List = s.DeviationList(gallery.Content.Results, true, DeviationList{ group.Gallery.List = s.DeviationList(content.Content.Results, true, DeviationList{
More: gallery.Content.HasMore, More: content.Content.HasMore,
}) })
} else { } else {
for _, x := range gallery.Content.Gruser.Page.Modules { for _, x := range content.Content.Gruser.Page.Modules {
if l := len(x.ModuleData.Folders.Results); l != 0 { if l := len(x.ModuleData.Folders.Results); l != 0 {
var folders strings.Builder var folders strings.Builder
folders.WriteString(`<h1 id="folders"><a href="#folder">#</a> Folders</h1><div class="folders"><br>`) folders.WriteString(`<h1 id="folders"><a href="#folder">#</a> Folders</h1><div class="folders"><br>`)
for _, x := range x.ModuleData.Folders.Results { for _, x := range x.ModuleData.Folders.Results {
if x.FolderId != -1 && x.Size != 0 {
folders.WriteString(`<div class="block folder-item">`) folders.WriteString(`<div class="block folder-item">`)
if !(x.Thumb.NSFW && !CFG.Nsfw) { if !(x.Thumb.NSFW && !CFG.Nsfw) {
@ -192,6 +143,7 @@ func (s skunkyart) GRUser() {
folders.WriteString("</div>") folders.WriteString("</div>")
} }
}
folders.WriteString(`</div><h1 id="content"><a href="#content">#</a> Content</h1>`) folders.WriteString(`</div><h1 id="content"><a href="#content">#</a> Content</h1>`)
group.Gallery.Folders = folders.String() group.Gallery.Folders = folders.String()
} }
@ -296,7 +248,7 @@ func (s skunkyart) Search() {
switch s.Type { switch s.Type {
case 'a', 't': case 'a', 't':
ss.Content, err = devianter.PerformSearch(s.Query, s.Page, s.Type) ss.Content, err = devianter.PerformSearch(s.Query, s.Page, s.Type)
case 'g': case 'g', 'f':
ss.Content, err = devianter.PerformSearch(s.Query, s.Page, s.Type, s.Args.Get("usr")) ss.Content, err = devianter.PerformSearch(s.Query, s.Page, s.Type, s.Args.Get("usr"))
case 'r': // скраппер, поскольку девиантартовцы зажопили гостевое API для поиска групп case 'r': // скраппер, поскольку девиантартовцы зажопили гостевое API для поиска групп
var ( var (

1
go.mod
View File

@ -2,6 +2,7 @@ module skunkyart
go 1.22.3 go 1.22.3
replace git.macaw.me/skunky/devianter v0.2.5 => /home/skunk/projects/devianter
require ( require (
git.macaw.me/skunky/devianter v0.2.5 git.macaw.me/skunky/devianter v0.2.5
golang.org/x/net v0.27.0 golang.org/x/net v0.27.0

View File

@ -25,7 +25,7 @@
}, },
{ {
"title": "bloat.cat", "title": "bloat.cat",
"country": "Romania", "country": "Germany",
"urls": { "urls": {
"clearnet": "https://skunky.bloat.cat" "clearnet": "https://skunky.bloat.cat"
}, },

View File

@ -3,14 +3,25 @@
{{template "head" . }} {{template "head" . }}
<main> <main>
<header> <header>
<h1><a href="{{.BasePath}}">HOME</a> | <a href="{{.BasePath}}dd">DD</a> <h1>
<a href="{{.BasePath}}">HOME</a>
| <a href="{{.BasePath}}dd">DD</a>
{{if ne .Type 'f'}}
| <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type={{if eq .Type 'a'}}gallery">Gallery{{else}}about">About{{end}}</a> | <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type={{if eq .Type 'a'}}gallery">Gallery{{else}}about">About{{end}}</a>
| <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type=gallery&atom=true">RSS</a></h1> | <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type=favourites">Favourites</a>
{{else}}
| <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type=about">About</a>
| <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type=gallery">Gallery</a>
| <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type=favourites">Favourites</a>
{{end}}
| <a href="group_user?q={{.Templates.GroupUser.GR.Owner.Username}}&type=gallery&atom=true">RSS</a>
</h1>
<form method="get" action="{{.BasePath}}search"> <form method="get" action="{{.BasePath}}search">
<input type="gallery" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false"> <input type="gallery" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<input type="hidden" name="usr" value="{{.Templates.GroupUser.GR.Owner.Username}}"> <input type="hidden" name="usr" value="{{.Templates.GroupUser.GR.Owner.Username}}">
<select name="type"> <select name="type">
<option value="gallery">Gallery</option> <option value="gallery">Gallery</option>
<option value="folders">Folders</option>
<option value="all">All</option> <option value="all">All</option>
<option value="tag">Tag</option> <option value="tag">Tag</option>
<option value="r">Groups</option> <option value="r">Groups</option>

View File

@ -5,12 +5,13 @@
"{{.QueryRaw}}" "{{.QueryRaw}}"
{{else if eq .Endpoint "post"}} {{else if eq .Endpoint "post"}}
{{.Templates.Deviation.Post.Deviation.Author.Username}} — {{.Templates.Deviation.Post.Deviation.Title}} {{.Templates.Deviation.Post.Deviation.Author.Username}} — {{.Templates.Deviation.Post.Deviation.Title}}
{{else if eq .Type 'a'}} {{else if eq .Endpoint "group_user"}}
{{if .Templates.GroupUser.GR.Owner.Username}} {{if eq .Type 'g'}}
{{.Templates.GroupUser.GR.Owner.Username}} gallery of
{{else}} {{else if eq .Type 'f'}}
gallery of {{.Templates.GroupUser.GR.Owner.Username}} favourites of
{{end}} {{end}}
{{.Templates.GroupUser.GR.Owner.Username}}
{{else}} {{else}}
{{.Endpoint}} {{.Endpoint}}
{{end}} {{end}}