aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlost+skunk <[email protected]>2024-08-14 19:18:06 +0300
committerlost+skunk <[email protected]>2024-08-14 19:18:06 +0300
commit2f8c35ba322e3c8c6e0bff8f7818d4eedf002928 (patch)
tree3158276fa91553bc87cbb751204d832b3616bfde
parent513543cc7a24330e3d9ce96d3b55e4726397af50 (diff)
downloadskunky-art-2f8c35ba322e3c8c6e0bff8f7818d4eedf002928.tar.gz
skunky-art-2f8c35ba322e3c8c6e0bff8f7818d4eedf002928.tar.bz2
skunky-art-2f8c35ba322e3c8c6e0bff8f7818d4eedf002928.zip
user favourites
-rw-r--r--INSTANCES.md2
-rw-r--r--TODO.md2
-rw-r--r--app/cache.go34
-rw-r--r--app/util.go59
-rw-r--r--app/wrapper.go144
-rw-r--r--go.mod1
-rw-r--r--instances.json2
-rw-r--r--static/html/gruser.htm17
-rw-r--r--static/html/head.htm11
9 files changed, 149 insertions, 123 deletions
diff --git a/INSTANCES.md b/INSTANCES.md
index 1637971..d032d24 100644
--- a/INSTANCES.md
+++ b/INSTANCES.md
@@ -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 |
|[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 |
|[lumaeris.com](https://skunkyart.lumaeris.com)|No|No|No| Yes | Yes | No | US | \ No newline at end of file
diff --git a/TODO.md b/TODO.md
index 84678b0..5a0da71 100644
--- a/TODO.md
+++ b/TODO.md
@@ -6,7 +6,7 @@
* ~~Исправить баг с навигацией по страницам~~ ✔️
* Сделать нормальное отображение ошибок
* ~~Сделать единицы в конфиге более понятными~~ ✔️
-* Добавить просмотр понравившихся артов пользователю
+* ~~Добавить просмотр понравившихся артов пользователю~~ ✔️
* Добавить возможность включить темплейты в бинарник [P]
* ~~Реализовать миниатюры и оптимизировать CSS под маленькие экраны~~ ✔️
* Написать Makefile и скрипт для автоматического развёртывания инстанса
diff --git a/app/cache.go b/app/cache.go
index dedba83..6506cfc 100644
--- a/app/cache.go
+++ b/app/cache.go
@@ -99,34 +99,36 @@ func (s skunkyart) DownloadAndSendMedia(subdomain, path string) {
func InitCacheSystem() {
c := &CFG.Cache
- os.Mkdir(c.Path, 0700)
for {
- dir, e := os.Open(c.Path)
- try(e)
- stat, e := dir.Stat()
- try(e)
-
- dirnames, e := dir.Readdirnames(-1)
- try(e)
- for _, a := range dirnames {
- a = c.Path + "/" + a
+ dir, err := os.ReadDir(c.Path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ os.Mkdir(c.Path, 0700)
+ continue
+ }
+ println(err.Error())
+ }
+
+ for _, file := range dir {
+ fileName := c.Path + "/" + file.Name()
+ fileInfo, err := file.Info()
+ try(err)
+
if c.Lifetime != "" {
now := time.Now().UnixMilli()
- f, _ := os.Stat(a)
- stat := f.Sys().(*syscall.Stat_t)
+ stat := fileInfo.Sys().(*syscall.Stat_t)
time := statTime(stat)
if time+lifetimeParsed <= now {
- try(os.RemoveAll(a))
+ try(os.RemoveAll(fileName))
}
}
- if c.MaxSize != 0 && stat.Size() > c.MaxSize {
- try(os.RemoveAll(a))
+ if c.MaxSize != 0 && fileInfo.Size() > c.MaxSize {
+ try(os.RemoveAll(fileName))
}
}
- dir.Close()
time.Sleep(time.Second * time.Duration(c.UpdateInterval))
}
}
diff --git a/app/util.go b/app/util.go
index a5b978d..8e8ef6e 100644
--- a/app/util.go
+++ b/app/util.go
@@ -16,6 +16,8 @@ import (
)
/* INTERNAL */
+var wr = io.WriteString
+
func exit(msg string, code int) {
println(msg)
os.Exit(code)
@@ -50,6 +52,63 @@ func RefreshInstances() {
}
// 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) {
var buf strings.Builder
tmp := template.New(file)
diff --git a/app/wrapper.go b/app/wrapper.go
index 5e8b6c1..e0e5054 100644
--- a/app/wrapper.go
+++ b/app/wrapper.go
@@ -2,9 +2,6 @@ package app
import (
"encoding/json"
- "io"
- "net/http"
- "net/url"
"regexp"
"strconv"
"strings"
@@ -14,65 +11,6 @@ import (
"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() {
if len(s.Query) < 1 {
s.ReturnHTTPError(400)
@@ -82,7 +20,7 @@ func (s skunkyart) GRUser() {
var g devianter.Group
g.Name = s.Query
var err error
- s.Templates.GroupUser.GR, err = g.GetGroup()
+ s.Templates.GroupUser.GR, err = g.Get()
try(err)
group := &s.Templates.GroupUser
@@ -146,51 +84,65 @@ func (s skunkyart) GRUser() {
}
}
- case 'g':
+ case 'g', 'f':
+ var all bool
+ var content devianter.Group
+
folderid, _ := strconv.Atoi(s.Args.Get("folder"))
+
+ if a := s.Args.Get("all"); a == "true" {
+ all = true
+ }
+
if s.Page == 0 {
s.Page++
}
- gallery, err := g.GetGallery(s.Page, folderid)
- try(err)
+ if s.Type == 'f' {
+ content = g.Favourites(s.Page, all, folderid)
+ } else {
+ content, err = g.Gallery(s.Page, folderid)
+ try(err)
+ }
- if folderid > 0 {
- group.Gallery.List = s.DeviationList(gallery.Content.Results, true, DeviationList{
- More: gallery.Content.HasMore,
+ if folderid > 0 || (s.Type == 'f' && all) {
+ group.Gallery.List = s.DeviationList(content.Content.Results, true, DeviationList{
+ More: content.Content.HasMore,
})
} 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 {
var folders strings.Builder
folders.WriteString(`<h1 id="folders"><a href="#folder">#</a> Folders</h1><div class="folders"><br>`)
for _, x := range x.ModuleData.Folders.Results {
- folders.WriteString(`<div class="block folder-item">`)
-
- if !(x.Thumb.NSFW && !CFG.Nsfw) {
- folders.WriteString(`<a href="`)
- folders.WriteString(ConvertDeviantArtUrlToSkunkyArt(x.Thumb.Url))
- folders.WriteString(`"><img loading="lazy" src="`)
- folders.WriteString(ParseMedia(x.Thumb.Media, x.Thumb.Title))
- folders.WriteString(`" title="`)
- folders.WriteString(x.Thumb.Title)
- folders.WriteString(`"></a>`)
- } else {
- folders.WriteString(`<h1>[ <span class="nsfw">NSFW</span> ]</h1>`)
+ if x.FolderId != -1 && x.Size != 0 {
+ folders.WriteString(`<div class="block folder-item">`)
+
+ if !(x.Thumb.NSFW && !CFG.Nsfw) {
+ folders.WriteString(`<a href="`)
+ folders.WriteString(ConvertDeviantArtUrlToSkunkyArt(x.Thumb.Url))
+ folders.WriteString(`"><img loading="lazy" src="`)
+ folders.WriteString(ParseMedia(x.Thumb.Media, x.Thumb.Title))
+ folders.WriteString(`" title="`)
+ folders.WriteString(x.Thumb.Title)
+ folders.WriteString(`"></a>`)
+ } else {
+ folders.WriteString(`<h1>[ <span class="nsfw">NSFW</span> ]</h1>`)
+ }
+ folders.WriteString("<br>")
+
+ folders.WriteString(`<a href="group_user?folder=`)
+ folders.WriteString(strconv.Itoa(x.FolderId))
+ folders.WriteString("&q=")
+ folders.WriteString(s.Query)
+ folders.WriteString("&type=")
+ folders.WriteString(string(s.Type))
+ folders.WriteString(`">`)
+ folders.WriteString(x.Name)
+ folders.WriteString(`</a>`)
+
+ folders.WriteString("</div>")
}
- folders.WriteString("<br>")
-
- folders.WriteString(`<a href="group_user?folder=`)
- folders.WriteString(strconv.Itoa(x.FolderId))
- folders.WriteString("&q=")
- folders.WriteString(s.Query)
- folders.WriteString("&type=")
- folders.WriteString(string(s.Type))
- folders.WriteString(`">`)
- folders.WriteString(x.Name)
- folders.WriteString(`</a>`)
-
- folders.WriteString("</div>")
}
folders.WriteString(`</div><h1 id="content"><a href="#content">#</a> Content</h1>`)
group.Gallery.Folders = folders.String()
@@ -296,7 +248,7 @@ func (s skunkyart) Search() {
switch s.Type {
case 'a', 't':
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"))
case 'r': // скраппер, поскольку девиантартовцы зажопили гостевое API для поиска групп
var (
diff --git a/go.mod b/go.mod
index 8016fa3..2b4844e 100644
--- a/go.mod
+++ b/go.mod
@@ -2,6 +2,7 @@ module skunkyart
go 1.22.3
+replace git.macaw.me/skunky/devianter v0.2.5 => /home/skunk/projects/devianter
require (
git.macaw.me/skunky/devianter v0.2.5
golang.org/x/net v0.27.0
diff --git a/instances.json b/instances.json
index cd95b78..74049be 100644
--- a/instances.json
+++ b/instances.json
@@ -25,7 +25,7 @@
},
{
"title": "bloat.cat",
- "country": "Romania",
+ "country": "Germany",
"urls": {
"clearnet": "https://skunky.bloat.cat"
},
diff --git a/static/html/gruser.htm b/static/html/gruser.htm
index c8227ef..6593951 100644
--- a/static/html/gruser.htm
+++ b/static/html/gruser.htm
@@ -3,14 +3,25 @@
{{template "head" . }}
<main>
<header>
- <h1><a href="{{.BasePath}}">HOME</a> | <a href="{{.BasePath}}dd">DD</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>
+ <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=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">
<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}}">
<select name="type">
<option value="gallery">Gallery</option>
+ <option value="folders">Folders</option>
<option value="all">All</option>
<option value="tag">Tag</option>
<option value="r">Groups</option>
diff --git a/static/html/head.htm b/static/html/head.htm
index f7f6b91..08ecf45 100644
--- a/static/html/head.htm
+++ b/static/html/head.htm
@@ -5,12 +5,13 @@
"{{.QueryRaw}}"
{{else if eq .Endpoint "post"}}
{{.Templates.Deviation.Post.Deviation.Author.Username}} — {{.Templates.Deviation.Post.Deviation.Title}}
- {{else if eq .Type 'a'}}
- {{if .Templates.GroupUser.GR.Owner.Username}}
- {{.Templates.GroupUser.GR.Owner.Username}}
- {{else}}
- gallery of {{.Templates.GroupUser.GR.Owner.Username}}
+ {{else if eq .Endpoint "group_user"}}
+ {{if eq .Type 'g'}}
+ gallery of
+ {{else if eq .Type 'f'}}
+ favourites of
{{end}}
+ {{.Templates.GroupUser.GR.Owner.Username}}
{{else}}
{{.Endpoint}}
{{end}}