mirror of
https://git.macaw.me/skunky/SkunkyArt.git
synced 2025-04-04 05:27:35 +03:00
Compare commits
12 commits
Author | SHA1 | Date | |
---|---|---|---|
|
71a07e074e | ||
|
e877802341 | ||
|
40d3d89623 | ||
|
048bb470ab | ||
|
32c61ec8ea | ||
|
92d4f4864a | ||
|
866429cafc | ||
|
e9de48656d | ||
|
86203ebb7b | ||
|
f692d1eb2d | ||
|
f857340dce | ||
|
911923fde1 |
18 changed files with 168 additions and 67 deletions
6
.dockerignore
Normal file
6
.dockerignore
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
cache
|
||||||
|
compose.yaml
|
||||||
|
*.json
|
||||||
|
LICENSE
|
||||||
|
*.md
|
||||||
|
services
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
**/cache
|
**/cache
|
||||||
|
**/compose.yaml
|
||||||
**/config.json
|
**/config.json
|
||||||
**/skunkyart
|
**/skunkyart
|
||||||
**/skunkyart-*
|
**/skunkyart-*
|
||||||
|
|
23
Dockerfile
Normal file
23
Dockerfile
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
ARG GO_VERSION=1.18
|
||||||
|
|
||||||
|
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION} AS build
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETARCH
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 GOARCH=${TARGETARCH} GOOS=${TARGETOS} go build -ldflags "-s -w -extldflags '-static'" && \
|
||||||
|
echo "skunkyart:x:10000:10000:SkunkyArt user:/:/sbin/nologin" > /etc/minimal-passwd && \
|
||||||
|
echo "skunkyart:x:10000:" > /etc/minimal-group
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
|
||||||
|
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
COPY --from=build /build/static /static
|
||||||
|
COPY --from=build /build/skunkyart /skunkyart
|
||||||
|
COPY --from=build /etc/minimal-passwd /etc/passwd
|
||||||
|
COPY --from=build /etc/minimal-group /etc/group
|
||||||
|
|
||||||
|
USER skunkyart
|
||||||
|
|
||||||
|
ENTRYPOINT ["/skunkyart"]
|
|
@ -2,8 +2,9 @@ JSON variant should be used from master — https://git.macaw.me/skunky/SkunkyAr
|
||||||
|
|
||||||
|Instance|Yggdrasil|I2P|Tor|NSFW|Proxifying|Modified Sources|Country|
|
|Instance|Yggdrasil|I2P|Tor|NSFW|Proxifying|Modified Sources|Country|
|
||||||
|:------:|:-------:|:-:|:-:|:--:|:--------:|:--------------:|:-----:|
|
|:------:|:-------:|:-:|:-:|:--:|:--------:|:--------------:|:-----:|
|
||||||
|[skunky.ebloid.ru](https://skunky.ebloid.ru/art)|[Yes](http://[201:eba5:d1fc:bf7b:cfcb:a811:4b8b:7ea3]/art)|No|No| No | Yes | No | Russia |
|
|[lost-skunk.cc](https://lost-skunk.cc/skunkyart)|[Yes](http://[201:f137:d1ac:920e:cd42:bfd1:1e83:da1d]/skunkyart)|No|No| No | Yes | No | Germany |
|
||||||
|[clovius.club](https://skunky.clovius.club)|No|No|No| Yes | Yes | No | Sweden |
|
|[orehus.club](https://sa.orehus.club)|No|No|No| Yes | No | No | Germany |
|
||||||
|[bloat.cat](https://skunky.bloat.cat)|No|No|No| Yes | Yes | No | Germany |
|
|[bloat.cat](https://skunky.bloat.cat)|No|No|No| Yes | Yes | No | Germany |
|
||||||
|[lumaeris.com](https://skunkyart.lumaeris.com)|No|No|No| Yes | Yes | No | Germany |
|
|[lumaeris.com](https://skunkyart.lumaeris.com)|No|No|No| Yes | Yes | No | Germany |
|
||||||
|[art.bloat.cat](https://art.bloat.cat)|No|No|No| Yes | Yes | No | Germany |
|
|[art.bloat.cat](https://art.bloat.cat)|No|No|No| Yes | Yes | No | Germany |
|
||||||
|
|[dc09.ru](https://sa.dc09.ru)|No|No|No| No | Yes | No | Russia |
|
|
@ -1,6 +1,10 @@
|
||||||
|
> [!NOTE]
|
||||||
|
> Currently, due to school, I cannot actively develop this project :(
|
||||||
|
> However, this does not mean that development has stopped. Just wait for the summer. For questions, write either to the Matrix room or to me in DM.
|
||||||
|
|
||||||
<img src="static/images/logo.png" alt="SkunkyArt" title="SkunkyArt Logo" width="20%" loading="lazy"/>
|
<img src="static/images/logo.png" alt="SkunkyArt" title="SkunkyArt Logo" width="20%" loading="lazy"/>
|
||||||
|
|
||||||
[](https://go.kde.org/matrix/#/#skunkyart:ebloid.ru)
|
[](https://go.kde.org/matrix/#/#skunkyart:gnulinux.club)
|
||||||
|
|
||||||
Instances: [`INSTANCES.md`](/skunky/SkunkyArt/src/branch/master/INSTANCES.md)
|
Instances: [`INSTANCES.md`](/skunky/SkunkyArt/src/branch/master/INSTANCES.md)
|
||||||
|
|
||||||
|
@ -21,6 +25,7 @@ To do this, you must either make a PR by adding your instance to the `instances.
|
||||||
1. the Instance must not use Cloudflare.
|
1. the Instance must not use Cloudflare.
|
||||||
2. If your instance has modified source code, you need to publish it to any free platform. For example, Github and Gitlab are not.
|
2. If your instance has modified source code, you need to publish it to any free platform. For example, Github and Gitlab are not.
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
* [vlnst](https://git.bloat.cat/vlnst) — wrote a Docker file.
|
||||||
* [Лис⚛](https://go.kde.org/matrix/#/@fox:matrix.org) — helped me understand Go and gave me a lot of useful advice on this language.
|
* [Лис⚛](https://go.kde.org/matrix/#/@fox:matrix.org) — helped me understand Go and gave me a lot of useful advice on this language.
|
||||||
* [meoww](https://codeberg.org/meoww) — translated some sentences into English and wrote a service for openrc
|
* [meoww](https://codeberg.org/meoww) — translated some sentences into English and wrote a service for openrc
|
||||||
|
|
||||||
|
@ -41,5 +46,6 @@ SkunkyArt 🦨 — альтернативный фронтенд к DeviantArt,
|
||||||
1. Инстанс не должен использовать Cloudflare итп.
|
1. Инстанс не должен использовать Cloudflare итп.
|
||||||
2. Если ваш инстанс имеет модифицированный исходный код, то вам нужно опубликовать его на любую свободную площадку. Например, Github и Gitlab таковыми не являются.
|
2. Если ваш инстанс имеет модифицированный исходный код, то вам нужно опубликовать его на любую свободную площадку. Например, Github и Gitlab таковыми не являются.
|
||||||
## Благодарности
|
## Благодарности
|
||||||
|
* [vlnst](https://git.bloat.cat/vlnst) — написал Docker-файл.
|
||||||
* [Лис⚛](https://go.kde.org/matrix/#/@fox:matrix.org) — помог разобраться в Go и много чего полезного посоветовал по этому языку.
|
* [Лис⚛](https://go.kde.org/matrix/#/@fox:matrix.org) — помог разобраться в Go и много чего полезного посоветовал по этому языку.
|
||||||
* [meoww](https://codeberg.org/meoww) — перевела некоторые предложения на английский язык и написала сервис для openrc
|
* [meoww](https://codeberg.org/meoww) — перевела некоторые предложения на английский язык и написала сервис для openrc
|
|
@ -41,12 +41,18 @@ func (a API) Error(description string, status int) {
|
||||||
func (a API) sendMedia(d *devianter.Deviation) {
|
func (a API) sendMedia(d *devianter.Deviation) {
|
||||||
mediaUrl, name := devianter.UrlFromMedia(d.Media)
|
mediaUrl, name := devianter.UrlFromMedia(d.Media)
|
||||||
a.main.SetFilename(name)
|
a.main.SetFilename(name)
|
||||||
|
|
||||||
if len(mediaUrl) != 0 {
|
if len(mediaUrl) != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if CFG.Proxy {
|
||||||
mediaUrl = mediaUrl[21:]
|
mediaUrl = mediaUrl[21:]
|
||||||
dot := strings.Index(mediaUrl, ".")
|
dot := strings.Index(mediaUrl, ".")
|
||||||
a.main.Writer.Header().Del("Content-Type")
|
a.main.Writer.Header().Del("Content-Type")
|
||||||
a.main.DownloadAndSendMedia(mediaUrl[:dot], mediaUrl[dot+11:])
|
a.main.DownloadAndSendMedia(mediaUrl[:dot], mediaUrl[dot+11:])
|
||||||
|
} else {
|
||||||
|
a.main.Writer.Header().Add("Location", mediaUrl)
|
||||||
|
a.main.Writer.WriteHeader(302)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
72
app/cache.go
72
app/cache.go
|
@ -38,17 +38,7 @@ func (s skunkyart) DownloadAndSendMedia(subdomain, path string) {
|
||||||
fileName := sha1.Sum([]byte(subdomain + path))
|
fileName := sha1.Sum([]byte(subdomain + path))
|
||||||
filePath := CFG.Cache.Path + "/" + hex.EncodeToString(fileName[:])
|
filePath := CFG.Cache.Path + "/" + hex.EncodeToString(fileName[:])
|
||||||
|
|
||||||
mx.Lock()
|
c := func() {
|
||||||
if tempFS[fileName] == nil {
|
|
||||||
tempFS[fileName] = &file{}
|
|
||||||
}
|
|
||||||
mx.Unlock()
|
|
||||||
|
|
||||||
if tempFS[fileName].Content != nil {
|
|
||||||
response = tempFS[fileName].Content
|
|
||||||
tempFS[fileName].Score += 2
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
file, err := os.Open(filePath)
|
file, err := os.Open(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if dwnld := Download(url.String()); dwnld.Status == 200 && dwnld.Headers["Content-Type"][0][:5] == "image" {
|
if dwnld := Download(url.String()); dwnld.Status == 200 && dwnld.Headers["Content-Type"][0][:5] == "image" {
|
||||||
|
@ -63,27 +53,44 @@ func (s skunkyart) DownloadAndSendMedia(subdomain, path string) {
|
||||||
try(e)
|
try(e)
|
||||||
response = file
|
response = file
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
if CFG.Cache.MemCache {
|
||||||
defer restore()
|
mx.Lock()
|
||||||
|
if tempFS[fileName] == nil {
|
||||||
|
tempFS[fileName] = &file{}
|
||||||
|
}
|
||||||
|
mx.Unlock()
|
||||||
|
|
||||||
mx.RLock()
|
if tempFS[fileName].Content != nil {
|
||||||
tempFS[fileName].Content = response
|
response = tempFS[fileName].Content
|
||||||
mx.RUnlock()
|
tempFS[fileName].Score += 2
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
c()
|
||||||
|
go func() {
|
||||||
|
defer restore()
|
||||||
|
|
||||||
for {
|
mx.RLock()
|
||||||
time.Sleep(1 * time.Minute)
|
tempFS[fileName].Content = response
|
||||||
|
mx.RUnlock()
|
||||||
|
|
||||||
mx.Lock()
|
for {
|
||||||
if tempFS[fileName].Score <= 0 {
|
time.Sleep(1 * time.Minute)
|
||||||
delete(tempFS, fileName)
|
|
||||||
|
mx.Lock()
|
||||||
|
if tempFS[fileName].Score <= 0 {
|
||||||
|
delete(tempFS, fileName)
|
||||||
|
mx.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tempFS[fileName].Score--
|
||||||
mx.Unlock()
|
mx.Unlock()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
tempFS[fileName].Score--
|
}()
|
||||||
mx.Unlock()
|
}
|
||||||
}
|
} else {
|
||||||
}()
|
c()
|
||||||
}
|
}
|
||||||
case CFG.Proxy:
|
case CFG.Proxy:
|
||||||
dwnld := Download(url.String())
|
dwnld := Download(url.String())
|
||||||
|
@ -112,6 +119,7 @@ func InitCacheSystem() {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var total int64
|
||||||
for _, file := range dir {
|
for _, file := range dir {
|
||||||
fileName := c.Path + "/" + file.Name()
|
fileName := c.Path + "/" + file.Name()
|
||||||
fileInfo, err := file.Info()
|
fileInfo, err := file.Info()
|
||||||
|
@ -128,9 +136,15 @@ func InitCacheSystem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.MaxSize != 0 && fileInfo.Size() > c.MaxSize {
|
total += fileInfo.Size()
|
||||||
try(os.RemoveAll(fileName))
|
// if c.MaxSize != 0 && fileInfo.Size() > c.MaxSize {
|
||||||
}
|
// try(os.RemoveAll(fileName))
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.MaxSize != 0 && total > c.MaxSize {
|
||||||
|
try(os.RemoveAll(c.Path))
|
||||||
|
os.Mkdir(c.Path, 0700)
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(time.Second * time.Duration(c.UpdateInterval))
|
time.Sleep(time.Second * time.Duration(c.UpdateInterval))
|
||||||
|
|
|
@ -12,12 +12,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var Release struct {
|
var Release struct {
|
||||||
Version string
|
Version string
|
||||||
Description string
|
Description string
|
||||||
}
|
}
|
||||||
|
|
||||||
type cache_config struct {
|
type cache_config struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
MemCache bool `json:"memcache"`
|
||||||
Path string
|
Path string
|
||||||
MaxSize int64 `json:"max-size"`
|
MaxSize int64 `json:"max-size"`
|
||||||
Lifetime string
|
Lifetime string
|
||||||
|
@ -93,9 +94,9 @@ func ExecuteConfig() {
|
||||||
|
|
||||||
About = instanceAbout{
|
About = instanceAbout{
|
||||||
Proxy: CFG.Proxy,
|
Proxy: CFG.Proxy,
|
||||||
Nsfw: CFG.Nsfw,
|
Nsfw: CFG.Nsfw,
|
||||||
}
|
}
|
||||||
|
|
||||||
static.StaticPath = CFG.StaticPath
|
static.StaticPath = CFG.StaticPath
|
||||||
devianter.UserAgent = CFG.UserAgent
|
devianter.UserAgent = CFG.UserAgent
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ func (s skunkyart) ParseComments(c devianter.Comments, daError devianter.Error)
|
||||||
|
|
||||||
if x.Parent > 0 {
|
if x.Parent > 0 {
|
||||||
cmmts.WriteString(` In reply to <a href="`)
|
cmmts.WriteString(` In reply to <a href="`)
|
||||||
cmmts.WriteString(Path)
|
cmmts.WriteString(s._pth)
|
||||||
cmmts.WriteString("#")
|
cmmts.WriteString("#")
|
||||||
cmmts.WriteString(strconv.Itoa(x.Parent))
|
cmmts.WriteString(strconv.Itoa(x.Parent))
|
||||||
cmmts.WriteString(`">`)
|
cmmts.WriteString(`">`)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Host, Path string
|
var Host string
|
||||||
|
|
||||||
func Router() {
|
func Router() {
|
||||||
parsepath := func(path string) map[int]string {
|
parsepath := func(path string) map[int]string {
|
||||||
|
@ -54,15 +54,14 @@ func Router() {
|
||||||
|
|
||||||
// функция, что управляет всем
|
// функция, что управляет всем
|
||||||
handle := func(w http.ResponseWriter, r *http.Request) {
|
handle := func(w http.ResponseWriter, r *http.Request) {
|
||||||
Path = r.URL.Path
|
path := parsepath(r.URL.Path)
|
||||||
path := parsepath(Path)
|
|
||||||
Host = "http://" + r.Host
|
Host = "http://" + r.Host
|
||||||
|
|
||||||
if h := r.Header["X-Forwarded-Proto"]; len(h) != 0 && h[0] == "https" {
|
if h := r.Header["X-Forwarded-Proto"]; len(h) != 0 && h[0] == "https" {
|
||||||
Host = "https://" + r.Host
|
Host = "https://" + r.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
var skunky = skunkyart{Version: Release.Version}
|
var skunky = skunkyart{Version: Release.Version}
|
||||||
|
skunky._pth = r.URL.Path
|
||||||
|
|
||||||
skunky.Args = r.URL.Query()
|
skunky.Args = r.URL.Query()
|
||||||
arg := skunky.Args.Get
|
arg := skunky.Args.Get
|
||||||
|
|
|
@ -63,6 +63,7 @@ type instanceAbout struct {
|
||||||
|
|
||||||
type skunkyart struct {
|
type skunkyart struct {
|
||||||
Writer http.ResponseWriter
|
Writer http.ResponseWriter
|
||||||
|
_pth string
|
||||||
|
|
||||||
Args url.Values
|
Args url.Values
|
||||||
Page int
|
Page int
|
||||||
|
@ -274,7 +275,7 @@ func (s skunkyart) NavBase(c DeviationList) string {
|
||||||
prevrev := func(msg string, page int, onpage bool) {
|
prevrev := func(msg string, page int, onpage bool) {
|
||||||
if !onpage {
|
if !onpage {
|
||||||
list.WriteString(`<a href="`)
|
list.WriteString(`<a href="`)
|
||||||
list.WriteString(Path)
|
list.WriteString(s._pth)
|
||||||
list.WriteString(`?p=`)
|
list.WriteString(`?p=`)
|
||||||
list.WriteString(strconv.Itoa(page))
|
list.WriteString(strconv.Itoa(page))
|
||||||
if s.Type != 0 {
|
if s.Type != 0 {
|
||||||
|
|
|
@ -36,13 +36,12 @@ func (s skunkyart) GRUser() {
|
||||||
for _, x := range g.Gruser.Page.Modules {
|
for _, x := range g.Gruser.Page.Modules {
|
||||||
switch x.Name {
|
switch x.Name {
|
||||||
case "about", "group_about":
|
case "about", "group_about":
|
||||||
switch g.Owner.Group {
|
if g.Owner.Group {
|
||||||
case true:
|
|
||||||
var about = &x.ModuleData.GroupAbout
|
var about = &x.ModuleData.GroupAbout
|
||||||
group.Group = true
|
group.Group = true
|
||||||
group.CreationDate = x.ModuleData.GroupAbout.FoundatedAt.UTC().String()
|
group.CreationDate = x.ModuleData.GroupAbout.FoundatedAt.UTC().String()
|
||||||
group.About.DescriptionFormatted = ParseDescription(about.Description)
|
group.About.DescriptionFormatted = ParseDescription(about.Description)
|
||||||
case false:
|
} else if false {
|
||||||
group.About.A = x.ModuleData.About
|
group.About.A = x.ModuleData.About
|
||||||
var about = &group.About.A
|
var about = &group.About.A
|
||||||
group.CreationDate = time.Unix(time.Now().Unix()-x.ModuleData.About.RegDate, 0).UTC().String()
|
group.CreationDate = time.Unix(time.Now().Unix()-x.ModuleData.About.RegDate, 0).UTC().String()
|
||||||
|
@ -186,6 +185,14 @@ func (s skunkyart) Deviation(author, postname string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if post.Post.Deviation.NSFW && !CFG.Nsfw {
|
||||||
|
s.Writer.WriteHeader(403)
|
||||||
|
wr(s.Writer, `<html><link rel="stylesheet" href="`+
|
||||||
|
UrlBuilder("stylesheet")+
|
||||||
|
`" /><h1>NSFW content are disabled on this instance.</h1></html>`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if post.Post.Comments.Total <= 50 {
|
if post.Post.Comments.Total <= 50 {
|
||||||
post.Post.Comments.Cursor = ""
|
post.Post.Comments.Cursor = ""
|
||||||
}
|
}
|
||||||
|
|
12
compose.example.yaml
Normal file
12
compose.example.yaml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
services:
|
||||||
|
skunkyart:
|
||||||
|
container_name: skunkyart
|
||||||
|
restart: unless-stopped
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:3003:3003"
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
volumes:
|
||||||
|
- ./config.json:/config.json:ro
|
||||||
|
- ./cache:/cache # Ensure cache folder has a 10000:10000 ownership.
|
|
@ -6,11 +6,12 @@
|
||||||
"path": "cache",
|
"path": "cache",
|
||||||
"lifetime": null,
|
"lifetime": null,
|
||||||
"max-size": 200,
|
"max-size": 200,
|
||||||
|
"memcache": false,
|
||||||
"update-interval": 5
|
"update-interval": 5
|
||||||
},
|
},
|
||||||
"static-path": "static",
|
"static-path": "static",
|
||||||
"download-proxy": "http://127.0.0.1:8080",
|
"download-proxy": "http://127.0.0.1:8080",
|
||||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
|
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
|
||||||
"proxy": true,
|
"proxy": true,
|
||||||
"nsfw": true
|
"nsfw": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"instances": [
|
"instances": [
|
||||||
{
|
{
|
||||||
"title": "skunky.ebloid.ru",
|
"title": "lost-skunk.cc",
|
||||||
"country": "Russia",
|
"country": "Germany",
|
||||||
"urls": {
|
"urls": {
|
||||||
"ygg": "http://[201:eba5:d1fc:bf7b:cfcb:a811:4b8b:7ea3]/art",
|
"ygg": "http://[201:f137:d1ac:920e:cd42:bfd1:1e83:da1d]/skunkyart",
|
||||||
"clearnet": "https://skunky.ebloid.ru/art"
|
"clearnet": "https://lost-skunk.cc/skunkyart"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"proxy": true,
|
"proxy": true,
|
||||||
|
@ -13,13 +13,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "clovius.club",
|
"title": "orehus.club",
|
||||||
"country": "Sweden",
|
"country": "Germany",
|
||||||
"urls": {
|
"urls": {
|
||||||
"clearnet": "https://skunky.clovius.club"
|
"clearnet": "https://sa.orehus.club"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"proxy": true,
|
"proxy": false,
|
||||||
"nsfw": true
|
"nsfw": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -55,6 +55,17 @@
|
||||||
"proxy": true,
|
"proxy": true,
|
||||||
"nsfw": true
|
"nsfw": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "dc09.ru",
|
||||||
|
"country": "Russia",
|
||||||
|
"urls": {
|
||||||
|
"clearnet": "https://sa.dc09.ru"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"proxy": true,
|
||||||
|
"nsfw": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/* TAGS */
|
/* TAGS */
|
||||||
html {
|
html {
|
||||||
font-family: Ubuntu;
|
font-family: ubuntu, system-ui;
|
||||||
background-color:black;
|
background-color:black;
|
||||||
color: rgb(234, 216, 216);
|
color: rgb(234, 216, 216);
|
||||||
}
|
}
|
||||||
|
@ -45,24 +45,22 @@ input:focus {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.block {
|
.block {
|
||||||
max-width: 20%;
|
padding: 0px 0px 6px 0px;
|
||||||
height: 0%;
|
border: 3px solid #000;
|
||||||
padding: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
border: 3px solid #091f19;
|
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
background-color: #091f19;
|
background-color: #091f19;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.block h1 {
|
||||||
|
padding: 8.5vh;
|
||||||
|
}
|
||||||
.block:hover {
|
.block:hover {
|
||||||
border: 3px solid #4d27d6;
|
border: 3px solid #4d27d6;
|
||||||
transition: 400ms;
|
transition: 400ms;
|
||||||
}
|
}
|
||||||
.block img, .plates .user-plate img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.block p {
|
.block p {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
@ -185,6 +183,20 @@ input:focus {
|
||||||
font-size: 60%;
|
font-size: 60%;
|
||||||
max-width: 80%
|
max-width: 80%
|
||||||
}
|
}
|
||||||
|
.block img, .plates .user-plate img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (orientation: landscape) {
|
||||||
|
.block {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
.block img, .plates .user-plate img {
|
||||||
|
width: 100%;
|
||||||
|
height: 30vh;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1462px) and (orientation: landscape) {
|
@media (max-width: 1462px) and (orientation: landscape) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<p>
|
<p>
|
||||||
SkunkyArt is an alternative frontend for deviantart.com, written in Go.
|
SkunkyArt is an alternative frontend for deviantart.com, written in Go.
|
||||||
</p>
|
</p>
|
||||||
<h3><a href="https://go.kde.org/matrix/#/#skunkyart:ebloid.ru" target="_blank">Room in [matrix]</a></h3>
|
<h3><a href="https://go.kde.org/matrix/#/#skunkyart:gnulinux.club" target="_blank">Room in [matrix]</a></h3>
|
||||||
<b>Instance settings:</b>
|
<b>Instance settings:</b>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>NSFW</b>: <span class="about-{{.Templates.About.Nsfw}}">{{if .Templates.About.Nsfw}}YES{{else}}NO{{end}}</span></li>
|
<li><b>NSFW</b>: <span class="about-{{.Templates.About.Nsfw}}">{{if .Templates.About.Nsfw}}YES{{else}}NO{{end}}</span></li>
|
||||||
|
@ -44,6 +44,6 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<p>Copyright <a href="https://go.kde.org/matrix/#/@softpigeones:ebloid.ru" target="_blank">lost+skunk</a>, X11. <a href="https://git.macaw.me/skunky/skunkyart/src/tag/v{{.Version}}" target="_blank">SkunkyArt v{{.Version}}</a></p>
|
<p>Copyright <a href="https://go.kde.org/matrix/#/@ls:gnulinux.club" target="_blank">lost+skunk</a>, X11. <a href="https://git.macaw.me/skunky/skunkyart/src/tag/v{{.Version}}" target="_blank">SkunkyArt v{{.Version}}</a></p>
|
||||||
</main>
|
</main>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
</form> <h1>| {{.Templates.GroupUser.GR.Owner.Username}}</h1>
|
</form> <h1>| {{.Templates.GroupUser.GR.Owner.Username}}</h1>
|
||||||
</header>
|
</header>
|
||||||
{{if eq .Type 'a'}}
|
{{if eq .Type 'a'}}
|
||||||
{{if ne .Templates.GroupUser.About.BG ""}}
|
{{if and (and (ne .Templates.About.Nsfw true) (ne .Templates.GroupUser.About.BGMeta.NSFW true)) (ne .Templates.GroupUser.About.BG "")}}
|
||||||
<a href="{{.Templates.GroupUser.About.BGMeta.Url}}" class="ubg"><img title="{{if ne .Templates.GroupUser.GR.Owner.Username .Templates.GroupUser.About.BGMeta.Author.Username}}
|
<a href="{{.Templates.GroupUser.About.BGMeta.Url}}" class="ubg"><img title="{{if ne .Templates.GroupUser.GR.Owner.Username .Templates.GroupUser.About.BGMeta.Author.Username}}
|
||||||
{{.Templates.GroupUser.About.BGMeta.Author.Username}} - {{end}}{{.Templates.GroupUser.About.BGMeta.Title}}" src="{{.Templates.GroupUser.About.BG}}"></a>
|
{{.Templates.GroupUser.About.BGMeta.Author.Username}} - {{end}}{{.Templates.GroupUser.About.BGMeta.Title}}" src="{{.Templates.GroupUser.About.BG}}"></a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue