v1.3.2
This commit is contained in:
parent
c39399403e
commit
191984b31e
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
**/cache
|
**/cache
|
||||||
**/config.json
|
**/config.json
|
||||||
**/skunkyart
|
**/skunkyart
|
||||||
|
**/skunkyart-*
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
JSON variant should be used from master — https://git.macaw.me/skunky/SkunkyArt/raw/branch/master/instances.json
|
||||||
|
|
||||||
|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 | 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 | Yes | 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 | 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 |
|
||||||
|
12
README.md
12
README.md
@ -7,6 +7,12 @@ Instances: [`INSTANCES.md`](/skunky/SkunkyArt/src/branch/master/INSTANCES.md)
|
|||||||
# EN 🇺🇸
|
# EN 🇺🇸
|
||||||
## Description
|
## Description
|
||||||
SkunkyArt 🦨 — alternative frontend for DevianArt, which works without JS.
|
SkunkyArt 🦨 — alternative frontend for DevianArt, which works without JS.
|
||||||
|
## Build (translated via DeepL)
|
||||||
|
It is recommended to build with the 'embed' tag because it embeds the presets in the binary. If you plan to modify the templates, then do not use this tag. You can also add the `-ldflags "-w -s"` argument (GCCGO has a different name for it — `gccgoflags`) to reduce the size of the output file. Here is an example:
|
||||||
|
|
||||||
|
`go build -tags embed -ldflags "-w -s"`
|
||||||
|
|
||||||
|
Pre-compiled binaries can be found in the [Releases](https://git.macaw.me/skunky/skunkyart/releases) tab.
|
||||||
## Setup
|
## Setup
|
||||||
The sample config is in the `config.example.json` file. For custom config, use `--config` option.
|
The sample config is in the `config.example.json` file. For custom config, use `--config` option.
|
||||||
See the [`SETUP.md`](/skunky/SkunkyArt/src/branch/master/SETUP.md) file for more info about directives.
|
See the [`SETUP.md`](/skunky/SkunkyArt/src/branch/master/SETUP.md) file for more info about directives.
|
||||||
@ -21,6 +27,12 @@ To do this, you must either make a PR by adding your instance to the `instances.
|
|||||||
# RU 🇷🇺
|
# RU 🇷🇺
|
||||||
## Описание
|
## Описание
|
||||||
SkunkyArt 🦨 — альтернативный фронтенд к DeviantArt, который полностью работает без JS (JavaScript).
|
SkunkyArt 🦨 — альтернативный фронтенд к DeviantArt, который полностью работает без JS (JavaScript).
|
||||||
|
## Сборка
|
||||||
|
Рекомендуется производить сборку с тегом 'embed', поскольку он встраивает заготовки в бинарный файл. Если вы планируете изменять заготовки, то не используйте этот тег. Также вы можете добавить аргумент `-ldflags "-w -s"` (у GCCGO он называется по-другому — `gccgoflags`) для уменьшения размера выходного файла. Вот пример:
|
||||||
|
|
||||||
|
`go build -tags embed -ldflags "-w -s"`
|
||||||
|
|
||||||
|
Готовые бинари находятся во вкладке [Releases](https://git.macaw.me/skunky/skunkyart/releases).
|
||||||
## Настройка
|
## Настройка
|
||||||
Пример конфига находится в файле `config.example.json`. Чтобы указать свой конфиг, используйте cli-аргумент `--config`.
|
Пример конфига находится в файле `config.example.json`. Чтобы указать свой конфиг, используйте cli-аргумент `--config`.
|
||||||
См. [`SETUP-RU.md`](/skunky/SkunkyArt/src/branch/master/SETUP-RU.md) для информации о настройки фронтенда.
|
См. [`SETUP-RU.md`](/skunky/SkunkyArt/src/branch/master/SETUP-RU.md) для информации о настройки фронтенда.
|
||||||
|
13
REDIRECTS.md
Normal file
13
REDIRECTS.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Search
|
||||||
|
* `deviantart.com/search?q=$QUERY` => `/search?q=$QUERY&type=all`
|
||||||
|
# Daily Deviations
|
||||||
|
* `deviantart.com` => `/dd`
|
||||||
|
# Deviations
|
||||||
|
* (`$USER_GROUP.deviantart.com/art/$ID`|`deviantart.com/$USER_GROUP/art/$ID`) => `/post/$USER_GROUP/$ID`
|
||||||
|
# Groups and users
|
||||||
|
## Main user page
|
||||||
|
* (`$USER_GROUP.deviantart.com`|`deviantart.com/$USER_GROUP`) => `/group_user?type=about&q=$USER_GROUP`
|
||||||
|
## Gallery
|
||||||
|
* (`$USER_GROUP.deviantart.com/gallery`|`deviantart.com/$USER_GROUP/gallery`) => `/group_user?type=gallery&q=$USER_GROUP`
|
||||||
|
## Favourites
|
||||||
|
* (`$USER_GROUP.deviantart.com/favourites`|`deviantart.com/$USER_GROUP/favourites`) => `/group_user?type=favourites&q=$USER_GROUP`
|
@ -12,13 +12,13 @@
|
|||||||
# Конфигурация
|
# Конфигурация
|
||||||
* `listen` — IP и порт для слушанья; заполняется по такой форме: ip:port
|
* `listen` — IP и порт для слушанья; заполняется по такой форме: ip:port
|
||||||
* `uri` — URI инстанса. Пример: `"uri":"/art/"` -> https://skunky.ebloid.ru/art/
|
* `uri` — URI инстанса. Пример: `"uri":"/art/"` -> https://skunky.ebloid.ru/art/
|
||||||
* `cache` — Система кеширования; по умолчанию выключена.
|
* `cache` — Система кеширования; по умолчанию выключена
|
||||||
* `enabled` — Состояние системы кеширования; требуется булёвое значение
|
* `enabled` — Состояние системы кеширования; требуется булёвое значение
|
||||||
* `path` — Полный путь до каталога, куда будет сохраняться кеш
|
* `path` — Полный путь до каталога, куда будет сохраняться кеш
|
||||||
* `lifetime` — Время жизни файла в кеше, требует целочисленное значение, дополненное суффиксом времени (см. 'Единицы времени')
|
* `lifetime` — Время жизни файла в кеше, требует целочисленное значение, дополненное суффиксом времени (см. 'Единицы времени')
|
||||||
* `max-size` — Максимальный размер файла
|
* `max-size` — Максимальный размер файла
|
||||||
* `update-interval` — Интервал для автоматической ротации кеша
|
* `update-interval` — Интервал для автоматической ротации кеша
|
||||||
* `dirs-to-memory` — Массив, заполнив который скопируются все файлы из указанных каталогов
|
* `static-path` — Строка, являющаяся путём до статики. SkunkyArt при запуске скопирует содержимое этого каталога в ОЗУ. Однако, если вы собрали фронтенд с тегом 'embed', то этого не произайдёт
|
||||||
* `download-proxy` — Адрес прокси для загрузки файлов
|
* `download-proxy` — Адрес прокси для загрузки файлов
|
||||||
* `user-agent` — Строка, которая используется в качестве User-Agent'а
|
* `user-agent` — Строка, которая используется в качестве User-Agent'а
|
||||||
|
|
||||||
|
2
SETUP.md
2
SETUP.md
@ -18,7 +18,7 @@ Time units:
|
|||||||
* `lifetime` — Cached file life time, requires numeric value, followed by multiplicative suffix (see Time Units for details)
|
* `lifetime` — Cached file life time, requires numeric value, followed by multiplicative suffix (see Time Units for details)
|
||||||
* `max-size` — Maximum file size in megabytes
|
* `max-size` — Maximum file size in megabytes
|
||||||
* `update-interval` — Automatic rotation interval
|
* `update-interval` — Automatic rotation interval
|
||||||
* `dirs-to-memory` — This setting determines which directories will be copied to RAM when SkunkyArt is started. Mandatory
|
* `static-path` — This setting determines path to static, which will be copied to RAM when SkunkyArt is started. Useless if you're use binary compiled with 'embed' tag.
|
||||||
* `download-proxy` — Proxy address for downloading files.
|
* `download-proxy` — Proxy address for downloading files.
|
||||||
* `user-agent` — String, which SkunkyArt uses as UA
|
* `user-agent` — String, which SkunkyArt uses as UA
|
||||||
|
|
||||||
|
81
app/api.go
81
app/api.go
@ -9,69 +9,68 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type API struct {
|
type API struct {
|
||||||
main *skunkyart
|
main *skunkyart
|
||||||
}
|
}
|
||||||
|
|
||||||
type info struct {
|
type info struct {
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Settings settingsParams `json:"settings"`
|
Settings settingsParams `json:"settings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a API) Info() {
|
func (a API) Info() {
|
||||||
json, err := json.Marshal(info{
|
json, err := json.Marshal(info{
|
||||||
Version: a.main.Version,
|
Version: a.main.Version,
|
||||||
Settings: settingsParams{
|
Settings: settingsParams{
|
||||||
Nsfw: CFG.Nsfw,
|
Nsfw: CFG.Nsfw,
|
||||||
Proxy: CFG.Proxy,
|
Proxy: CFG.Proxy,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
try(err)
|
try(err)
|
||||||
a.main.Writer.Write(json)
|
a.main.Writer.Write(json)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a API) Error(description string, status int) {
|
func (a API) Error(description string, status int) {
|
||||||
a.main.Writer.WriteHeader(status)
|
a.main.Writer.WriteHeader(status)
|
||||||
var response strings.Builder
|
var response strings.Builder
|
||||||
response.WriteString(`{"error":"`)
|
response.WriteString(`{"error":"`)
|
||||||
response.WriteString(description)
|
response.WriteString(description)
|
||||||
response.WriteString(`"}`)
|
response.WriteString(`"}`)
|
||||||
wr(a.main.Writer, response.String())
|
wr(a.main.Writer, response.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
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:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: сделать фильтры
|
// TODO: сделать фильтры
|
||||||
func (a API) Random() {
|
func (a API) Random() {
|
||||||
for attempt := 1;; {
|
for attempt := 1; ; {
|
||||||
if attempt > 3 {
|
if attempt > 3 {
|
||||||
a.Error("Sorry, butt NSFW on this are disabled, and the instance failed to find a random art without NSFW", 500)
|
a.Error("Sorry, butt NSFW on this are disabled, and the instance failed to find a random art without NSFW", 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err, daErr := devianter.PerformSearch(string(rand.Intn(999)), rand.Intn(30), 'a')
|
s, err, daErr := devianter.PerformSearch(string(rand.Intn(999)), rand.Intn(30), 'a')
|
||||||
try(err)
|
try(err)
|
||||||
if daErr.RAW != nil {
|
if daErr.RAW != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
deviation := &s.Results[rand.Intn(len(s.Results))]
|
deviation := &s.Results[rand.Intn(len(s.Results))]
|
||||||
|
|
||||||
if deviation.NSFW && !CFG.Nsfw {
|
if deviation.NSFW && !CFG.Nsfw {
|
||||||
attempt++
|
attempt++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
a.sendMedia(deviation)
|
a.sendMedia(deviation)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ func (s skunkyart) DownloadAndSendMedia(subdomain, path string) {
|
|||||||
url.WriteString(".wixmp.com/")
|
url.WriteString(".wixmp.com/")
|
||||||
url.WriteString(path)
|
url.WriteString(path)
|
||||||
if t := s.Args.Get("token"); t != "" {
|
if t := s.Args.Get("token"); t != "" {
|
||||||
url.WriteString("?token=")
|
url.WriteString("?token=")
|
||||||
url.WriteString(t)
|
url.WriteString(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
var response []byte
|
var response []byte
|
||||||
|
@ -56,13 +56,11 @@ func ExecuteConfig() {
|
|||||||
if CFG.cfg != "" {
|
if CFG.cfg != "" {
|
||||||
f, err := os.ReadFile(CFG.cfg)
|
f, err := os.ReadFile(CFG.cfg)
|
||||||
tryWithExitStatus(err, 1)
|
tryWithExitStatus(err, 1)
|
||||||
|
|
||||||
tryWithExitStatus(json.Unmarshal(f, &CFG), 1)
|
tryWithExitStatus(json.Unmarshal(f, &CFG), 1)
|
||||||
if CFG.Cache.Enabled && !CFG.Proxy {
|
if CFG.Cache.Enabled && !CFG.Proxy {
|
||||||
exit("Incompatible settings detected: cannot use caching media content without proxy", 1)
|
exit("Incompatible settings detected: cannot use caching media content without proxy", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
static.StaticPath = CFG.StaticPath
|
|
||||||
if CFG.Cache.Enabled {
|
if CFG.Cache.Enabled {
|
||||||
if CFG.Cache.Lifetime != "" {
|
if CFG.Cache.Lifetime != "" {
|
||||||
var duration int64
|
var duration int64
|
||||||
@ -92,6 +90,13 @@ func ExecuteConfig() {
|
|||||||
CFG.Cache.MaxSize *= 1024 ^ 2
|
CFG.Cache.MaxSize *= 1024 ^ 2
|
||||||
go InitCacheSystem()
|
go InitCacheSystem()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
About = instanceAbout{
|
||||||
|
Proxy: CFG.Proxy,
|
||||||
|
Nsfw: CFG.Nsfw,
|
||||||
|
}
|
||||||
|
|
||||||
|
static.StaticPath = CFG.StaticPath
|
||||||
devianter.UserAgent = CFG.UserAgent
|
devianter.UserAgent = CFG.UserAgent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package app
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
u "net/url"
|
url "net/url"
|
||||||
"skunkyart/static"
|
"skunkyart/static"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -73,7 +73,7 @@ func Router() {
|
|||||||
skunky.Writer = w
|
skunky.Writer = w
|
||||||
skunky.BasePath = CFG.URI
|
skunky.BasePath = CFG.URI
|
||||||
skunky.QueryRaw = arg("q")
|
skunky.QueryRaw = arg("q")
|
||||||
skunky.Query = u.QueryEscape(skunky.QueryRaw)
|
skunky.Query = url.QueryEscape(skunky.QueryRaw)
|
||||||
skunky.Page = p
|
skunky.Page = p
|
||||||
|
|
||||||
if t := arg("type"); len(t) > 0 {
|
if t := arg("type"); len(t) > 0 {
|
||||||
@ -84,12 +84,21 @@ func Router() {
|
|||||||
skunky.Atom = true
|
skunky.Atom = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if CFG.Proxy {
|
||||||
|
w.Header().Add("Content-Security-Policy", "default-src 'self'; script-src 'none'; style-src 'self' 'unsafe-inline'")
|
||||||
|
} else {
|
||||||
|
w.Header().Add("Content-Security-Policy", "default-src 'self'; img-src 'self' *.wixmp.com; script-src 'none'; style-src 'self' 'unsafe-inline'")
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Add("X-Frame-Options", "DENY")
|
||||||
|
|
||||||
switch skunky.Endpoint {
|
switch skunky.Endpoint {
|
||||||
// main
|
// main
|
||||||
case "":
|
case "":
|
||||||
skunky.ExecuteTemplate("index.htm", "html", &CFG.URI)
|
skunky.ExecuteTemplate("index.htm", "html", &CFG.URI)
|
||||||
case "about":
|
case "about":
|
||||||
skunky.About()
|
skunky.Templates.About = About
|
||||||
|
skunky.ExecuteTemplate("about.htm", "html", &skunky)
|
||||||
case "post":
|
case "post":
|
||||||
skunky.Deviation(path[2], path[3])
|
skunky.Deviation(path[2], path[3])
|
||||||
case "search":
|
case "search":
|
||||||
@ -120,12 +129,12 @@ func Router() {
|
|||||||
case "api":
|
case "api":
|
||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
switch path[2] {
|
switch path[2] {
|
||||||
case "instance":
|
case "instance":
|
||||||
skunky.API.Info()
|
skunky.API.Info()
|
||||||
case "random":
|
case "random":
|
||||||
skunky.API.Random()
|
skunky.API.Random()
|
||||||
default:
|
default:
|
||||||
skunky.API.Error("Not Found", 404)
|
skunky.API.Error("Not Found", 404)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 404
|
// 404
|
||||||
|
23
app/util.go
23
app/util.go
@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -40,18 +41,26 @@ func restore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var instances []byte
|
var instances []byte
|
||||||
|
var About instanceAbout
|
||||||
|
|
||||||
func RefreshInstances() {
|
func RefreshInstances() {
|
||||||
for {
|
for {
|
||||||
func() {
|
func() {
|
||||||
defer restore()
|
defer restore()
|
||||||
instances = Download("https://git.macaw.me/skunky/SkunkyArt/raw/branch/master/instances.json").Body
|
instances = Download("https://git.macaw.me/skunky/SkunkyArt/raw/branch/master/instances.json").Body
|
||||||
|
try(json.Unmarshal(instances, &About))
|
||||||
}()
|
}()
|
||||||
time.Sleep(1 * time.Hour)
|
time.Sleep(1 * time.Hour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// some crap for frontend
|
// some crap for frontend
|
||||||
|
type instanceAbout struct {
|
||||||
|
Proxy bool
|
||||||
|
Nsfw bool
|
||||||
|
Instances []settings
|
||||||
|
}
|
||||||
|
|
||||||
type skunkyart struct {
|
type skunkyart struct {
|
||||||
Writer http.ResponseWriter
|
Writer http.ResponseWriter
|
||||||
|
|
||||||
@ -63,15 +72,11 @@ type skunkyart struct {
|
|||||||
BasePath, Endpoint string
|
BasePath, Endpoint string
|
||||||
Query, QueryRaw string
|
Query, QueryRaw string
|
||||||
|
|
||||||
API API
|
API API
|
||||||
Version string
|
Version string
|
||||||
|
|
||||||
Templates struct {
|
Templates struct {
|
||||||
About struct {
|
About instanceAbout
|
||||||
Proxy bool
|
|
||||||
Nsfw bool
|
|
||||||
Instances []settings
|
|
||||||
}
|
|
||||||
|
|
||||||
SomeList string
|
SomeList string
|
||||||
DDStrips string
|
DDStrips string
|
||||||
@ -132,7 +137,7 @@ func UrlBuilder(strs ...string) string {
|
|||||||
str.WriteString(CFG.URI)
|
str.WriteString(CFG.URI)
|
||||||
for n, x := range strs {
|
for n, x := range strs {
|
||||||
str.WriteString(x)
|
str.WriteString(x)
|
||||||
if n := n+1; n < l && len(strs[n]) != 0 && !(strs[n][0] == '?' || strs[n][0] == '&') && !(x[0] == '?' || x[0] == '&') {
|
if n := n + 1; n < l && len(strs[n]) != 0 && !(strs[n][0] == '?' || strs[n][0] == '&') && !(x[0] == '?' || x[0] == '&') {
|
||||||
str.WriteString("/")
|
str.WriteString("/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,6 +220,8 @@ func ParseMedia(media devianter.Media, thumb ...int) string {
|
|||||||
filename = "image.gif"
|
filename = "image.gif"
|
||||||
}
|
}
|
||||||
return UrlBuilder("media", "file", mediaUrl[:dot], mediaUrl[dot+11:], "&filename=", filename)
|
return UrlBuilder("media", "file", mediaUrl[:dot], mediaUrl[dot+11:], "&filename=", filename)
|
||||||
|
} else if !CFG.Proxy {
|
||||||
|
return mediaUrl
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -24,8 +23,8 @@ func (s skunkyart) GRUser() {
|
|||||||
s.Templates.GroupUser.GR, err, daError = g.Get()
|
s.Templates.GroupUser.GR, err, daError = g.Get()
|
||||||
try(err)
|
try(err)
|
||||||
if daError.RAW != nil {
|
if daError.RAW != nil {
|
||||||
s.Error(daError)
|
s.Error(daError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
group := &s.Templates.GroupUser
|
group := &s.Templates.GroupUser
|
||||||
@ -68,7 +67,7 @@ func (s skunkyart) GRUser() {
|
|||||||
group.About.Interests += interest.String()
|
group.About.Interests += interest.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group.About.Comments = s.ParseComments(devianter.GetComments(strconv.Itoa(group.GR.Gruser.ID),"",s.Page,4))
|
group.About.Comments = s.ParseComments(devianter.GetComments(strconv.Itoa(group.GR.Gruser.ID), "", s.Page, 4))
|
||||||
|
|
||||||
case "cover_deviation":
|
case "cover_deviation":
|
||||||
group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation
|
group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation
|
||||||
@ -225,8 +224,8 @@ func (s skunkyart) Deviation(author, postname string) {
|
|||||||
func (s skunkyart) DD() {
|
func (s skunkyart) DD() {
|
||||||
dd, err := devianter.GetDailyDeviations(s.Page)
|
dd, err := devianter.GetDailyDeviations(s.Page)
|
||||||
if err.RAW != nil {
|
if err.RAW != nil {
|
||||||
s.Error(err)
|
s.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var strips strings.Builder
|
var strips strings.Builder
|
||||||
for _, x := range dd.Strips {
|
for _, x := range dd.Strips {
|
||||||
@ -312,12 +311,13 @@ func (s skunkyart) Search() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try(err)
|
try(err)
|
||||||
if daError.RAW != nil {
|
|
||||||
s.Error(daError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Type != 'r' {
|
if s.Type != 'r' {
|
||||||
|
if daError.RAW != nil {
|
||||||
|
s.Error(daError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ss.List = s.DeviationList(ss.Content.Results, false, DeviationList{
|
ss.List = s.DeviationList(ss.Content.Results, false, DeviationList{
|
||||||
Pages: ss.Content.Pages,
|
Pages: ss.Content.Pages,
|
||||||
More: ss.Content.HasMore,
|
More: ss.Content.HasMore,
|
||||||
@ -339,10 +339,3 @@ func (s skunkyart) Emojitar(name string) {
|
|||||||
}
|
}
|
||||||
wr(s.Writer, ae)
|
wr(s.Writer, ae)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s skunkyart) About() {
|
|
||||||
s.Templates.About.Nsfw = CFG.Nsfw
|
|
||||||
s.Templates.About.Proxy = CFG.Proxy
|
|
||||||
try(json.Unmarshal(instances, &s.Templates.About))
|
|
||||||
s.ExecuteTemplate("about.htm", "html", &s)
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"listen": "0.0.0.0:3003",
|
"listen": "0.0.0.0:3003",
|
||||||
"uri": "/huy/",
|
"uri": "/",
|
||||||
"cache": {
|
"cache": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"path": "cache",
|
"path": "cache",
|
||||||
@ -12,5 +12,5 @@
|
|||||||
"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": false
|
"nsfw": true
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
"clearnet": "https://skunky.ebloid.ru/art"
|
"clearnet": "https://skunky.ebloid.ru/art"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"nsfw": false,
|
"proxy": true,
|
||||||
"proxy": false
|
"nsfw": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -19,8 +19,8 @@
|
|||||||
"clearnet": "https://skunky.clovius.club"
|
"clearnet": "https://skunky.clovius.club"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"nsfw": true,
|
"proxy": true,
|
||||||
"proxy": true
|
"nsfw": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -30,8 +30,8 @@
|
|||||||
"clearnet": "https://skunky.bloat.cat"
|
"clearnet": "https://skunky.bloat.cat"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"nsfw": true,
|
"proxy": true,
|
||||||
"proxy": true
|
"nsfw": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -41,8 +41,8 @@
|
|||||||
"clearnet": "https://skunkyart.lumaeris.com"
|
"clearnet": "https://skunkyart.lumaeris.com"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"nsfw": true,
|
"proxy": true,
|
||||||
"proxy": true
|
"nsfw": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -52,8 +52,8 @@
|
|||||||
"clearnet": "https://art.bloat.cat"
|
"clearnet": "https://art.bloat.cat"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"nsfw": true,
|
"proxy": true,
|
||||||
"proxy": true
|
"nsfw": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
2
main.go
2
main.go
@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app.Release.Version = "1.3.2-alpha"
|
app.Release.Version = "1.3.2"
|
||||||
app.Release.Description = "Two API endpoints and template embedding into binary"
|
app.Release.Description = "Two API endpoints and template embedding into binary"
|
||||||
go app.RefreshInstances()
|
go app.RefreshInstances()
|
||||||
|
|
||||||
|
@ -19,11 +19,10 @@ header h1 {
|
|||||||
header form {
|
header form {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
header {
|
header, form {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
form {
|
form {
|
||||||
font-size: 0;
|
|
||||||
border: solid #164e3e 1px;
|
border: solid #164e3e 1px;
|
||||||
max-width: fit-content;
|
max-width: fit-content;
|
||||||
}
|
}
|
||||||
@ -147,22 +146,19 @@ input:focus {
|
|||||||
font-size: 80%
|
font-size: 80%
|
||||||
}
|
}
|
||||||
|
|
||||||
center form {
|
header {
|
||||||
font-size: 60%
|
margin-left: 3%;
|
||||||
}
|
|
||||||
|
|
||||||
header form {
|
|
||||||
font-size: 60%;
|
|
||||||
max-width: unset;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
header, center {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: block;
|
display: inline-block;
|
||||||
clear: both;
|
clear: both;
|
||||||
font-size: 200%;
|
font-size: 200%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
font-size: 60%;
|
||||||
|
border: solid #164e3e 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
display: inherit;
|
display: inherit;
|
||||||
|
@ -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:ebloid.ru" 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>
|
||||||
|
@ -21,5 +21,6 @@
|
|||||||
<meta name="referrer" content="no-referrer" />
|
<meta name="referrer" content="no-referrer" />
|
||||||
<link rel="stylesheet" href="{{.BasePath}}stylesheet">
|
<link rel="stylesheet" href="{{.BasePath}}stylesheet">
|
||||||
<link rel="icon" type="image/x-icon" href="{{.BasePath}}favicon.ico">
|
<link rel="icon" type="image/x-icon" href="{{.BasePath}}favicon.ico">
|
||||||
|
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.4, user-scalable=no; user-scalable=0"/>
|
||||||
</head>
|
</head>
|
||||||
{{end}}
|
{{end}}
|
@ -4,9 +4,75 @@
|
|||||||
<title>SkunkyArt</title>
|
<title>SkunkyArt</title>
|
||||||
<link rel="stylesheet" href="{{.}}stylesheet"/>
|
<link rel="stylesheet" href="{{.}}stylesheet"/>
|
||||||
<link rel="icon" type="image/x-icon" href="{{.}}favicon.ico">
|
<link rel="icon" type="image/x-icon" href="{{.}}favicon.ico">
|
||||||
|
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=0.4, user-scalable=no; user-scalable=0"/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
main {
|
||||||
|
display: flex;
|
||||||
|
max-width: fit-content;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 50%;
|
||||||
|
transform: translate(50%, -50%);
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
transform: translate(0, 50%);
|
||||||
|
margin-left: 4%;
|
||||||
|
flex-basis: 100%;
|
||||||
|
height: 30%;
|
||||||
|
display: block;
|
||||||
|
max-width: fit-content;
|
||||||
|
}
|
||||||
|
div h1, form {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
div form {
|
||||||
|
font-size: 100%;
|
||||||
|
max-width: 100%
|
||||||
|
}
|
||||||
|
div form input {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 30%;
|
||||||
|
height: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (orientation: portrait) {
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
width: 200%;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
form {
|
||||||
|
width: 200%;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
margin: -25%;
|
||||||
|
margin-top: auto;
|
||||||
|
width: 200%;
|
||||||
|
}
|
||||||
|
div h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 1155px) and (orientation: landscape) {
|
||||||
|
img {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<main>
|
<main>
|
||||||
<center>
|
<img src="{{.}}favicon.ico" title="SkunkyArt logo" draggable="false">
|
||||||
|
<div>
|
||||||
|
<h1><a href="{{.}}dd">Daily Deviations</a> | <a href="{{.}}about">About</a></h1>
|
||||||
<form method="get" action="{{.}}search">
|
<form method="get" action="{{.}}search">
|
||||||
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
|
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
|
||||||
<select name="type">
|
<select name="type">
|
||||||
@ -16,7 +82,9 @@
|
|||||||
</select>
|
</select>
|
||||||
<button type="submit">Search!</button>
|
<button type="submit">Search!</button>
|
||||||
</form>
|
</form>
|
||||||
<h1><a href="{{.}}dd">Daily Deviations</a> | <a href="{{.}}about">About</a> | <a href="https://git.macaw.me/skunky/SkunkyArt" target="_blank">Source Code</a></h1>
|
<h1 style="margin-top: 5%; font-size: 200%; text-align: center;">
|
||||||
</center>
|
<a href="https://git.macaw.me/skunky/SkunkyArt" target="_blank" title="Source Code">SkunkyArt</a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user