From c5514c3875b9b782688047d547dfd6663a5b77bb Mon Sep 17 00:00:00 2001 From: lost+skunk Date: Thu, 1 Aug 2024 22:48:05 +0300 Subject: [PATCH] v1.3 --- INSTANCES.md | 7 ++ README.md | 90 ++++------------ SETUP-RU.md | 42 ++++++++ SETUP.md | 42 ++++++++ TODO.md | 5 +- app/cli.go | 166 +++++++++++++++++++++++++++++ app/config.go | 48 ++------- app/router.go | 6 +- app/util.go | 23 +++- app/wrapper.go | 112 +++++++++---------- config.example.json | 14 +-- go.mod | 4 +- go.sum | 4 +- html/about.htm | 63 +++++------ html/daily.htm | 1 + html/deviantion.htm | 1 + html/gruser.htm | 1 + html/index.htm | 1 + html/search.htm | 1 + instances.json | 20 ++-- main.go | 18 +++- services/skunkyart.example.openrc | 23 ++-- services/skunkyart.example.service | 2 +- 23 files changed, 445 insertions(+), 249 deletions(-) create mode 100644 INSTANCES.md create mode 100644 SETUP-RU.md create mode 100644 SETUP.md create mode 100644 app/cli.go diff --git a/INSTANCES.md b/INSTANCES.md new file mode 100644 index 0000000..1637971 --- /dev/null +++ b/INSTANCES.md @@ -0,0 +1,7 @@ +|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 | +|[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 | +|[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/README.md b/README.md index ba6e4b3..6eaa831 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,33 @@ -SkunkyArt +SkunkyArt [![Matrix room](https://img.shields.io/badge/matrix-000000?style=for-the-badge&logo=Matrix&logoColor=white)](https://go.kde.org/matrix/#/#skunkyart:ebloid.ru) -# Instances -|Instance|Yggdrasil|I2P|Tor|NSFW|Proxifying|Country| -|:------:|:-------:|:-:|:-:|:--:|:--------:|:-----:| -|[skunky.ebloid.ru](https://skunky.ebloid.ru/art)|[Yes](http://[201:eba5:d1fc:bf7b:cfcb:a811:4b8b:7ea3]/art)|No|No| No | No | Russia | -|[clovius.club](https://skunky.clovius.club)|No|No|No| Yes | Yes | Sweden | -|[bloat.cat](https://skunky.bloat.cat)|No|No|No| Yes | Yes | Romania | -|[frontendfriendly.xyz](https://skunkyart.frontendfriendly.xyz)|No|No|No| Yes | Yes | Finland | -|[lumaeris.com](https://skunkyart.lumaeris.com)|No|No|No| Yes | Yes | US | + +Instances: [`INSTANCES.md`](https://git.macaw.me/skunky/SkunkyArt/src/branch/master/INSTANCES.md) # EN 🇺🇸 ## Description -SkunkyArt 🦨 -- alternative frontend to DeviantArt, which will work without problems even on quite old hardware, due to the lack of JavaScript. -## Config -The sample config is in the `config.example.json` file. To specify your own path to the config, use the CLI argument `-c` or `--config`. -* `listen` -- the address and port on which SkunkyArt will listen -* `base-path` -- the path to the instance. Example: `"base-path":"/art/"` -> https://skunky.ebloid.ru/art/ -* `cache` -- caching system; default is off. - * `path` -- the path to the cache - * `lifetime` -- the lifetime of the file in the cache. Units: i, h, d, w, m, y. I -- minute, all other units I think are self-explanatory. - * `max-size` -- maximum file size in megabytes. -* `dirs-to-memory` -- this setting determines which directories will be copied to RAM when SkunkyArt is started. Mandatory -* `download-proxy` -- proxy address for downloading files. -## Examples of reverse proxies -Nginx: -```apache -server { - listen 443 ssl; - server_name skunky.example.com; - - location ((BASE URL)) { # if you have a separate subdomain for the frontend, insert '/' instead of '((BASE URL)))'. - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - proxy_http_version 1.1; - proxy_pass http://((IP)):((PORT)); - } -} -``` -Pretty much business as usual, except for the [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) header setting. -## How do I add my instance to the list? -To do this, you must either make a PR by adding your instance to the `instances.json` and `README.md` files, or create an Issue, or report it to the room in Matrix. I don't think it needs any description. However, be warned, this list has a couple rules: +SkunkyArt 🦨 — alternative frontend for DevianArt, which works without JS. +## Setup +The sample config is in the `config.example.json` file. For custom config, use `--config` option. +See the [`SETUP.md`](https://git.macaw.me/skunky/SkunkyArt/src/branch/master/SETUP.md) file for more info about directives. +## Adding instance to the list +To do this, you must either make a PR by adding your instance to the `instances.json` and `INSTANCES.md` files (you can use `--add-instance` cli-argument to automatically add the instance to these files), or create an Issue, or report it to the room in Matrix. Keep in mind that your instance must comply with the following rules: 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. ## Acknowledgements -* [Лис⚛](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 # RU 🇷🇺 ## Описание -SkunkyArt 🦨 -- альтернативный фронтенд к DeviantArt, который будет работать без проблем даже на довольно старом оборудовании, за счёт отсутствия JavaScript. -## Конфиг -Пример конфига находится в файле `config.example.json`. Чтобы указать свой путь до конфига, используйте CLI-аргумент `-c` или `--config`. -* `listen` -- адрес и порт, на котором будет слушать SkunkyArt -* `base-path` -- путь к инстансу. Пример: `"base-path": "/art/"` -> https://skunky.ebloid.ru/art/ -* `cache` -- система кеширования; по умолчанию - выкл. - * `path` -- путь до кеша - * `lifetime` -- время жизни файла в кеше. Единицы измерения: i, h, d, w, m, y. I -- минута, всё остальные единицы измерения, я считаю понятными и без объяснения. - * `max-size` -- максимальный размер файла в мегабайтах -* `dirs-to-memory` -- данная настройка определяет какие каталоги будут скопированы в ОЗУ при запуске SkunkyArt. Обязательна -* `download-proxy` -- адрес прокси для загрузки файлов -## Примеры reverse-прокси -Nginx: -```apache -server { - listen 443 ssl; - server_name skunky.example.com; - - location ((BASE URL)) { # если у вас отдельный поддомен для фронтенда, вместо '((BASE URL))' вставляйте '/' - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - proxy_http_version 1.1; - proxy_pass http://((IP)):((PORT)); - } -} -``` -В целом, всё как обычно, за исключением настройки заголовка [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto). -## Как добавить свой инстанс в список? -Чтобы это сделать, вы должны либо сделать PR, добавив в файлы `instances.json` и `README.md` свой инстанс, либо создать Issue, или сообщить о нём в комнате в Matrix. Думаю, он не нуждается в описании. Однако учтите, у этого списка есть пара правил: -1. Инстанс не должен использовать Cloudflare. +SkunkyArt 🦨 — альтернативный фронтенд к DeviantArt, который полностью работает без JS (JavaScript). +## Настройка +Пример конфига находится в файле `config.example.json`. Чтобы указать свой конфиг, используйте cli-аргумент `--config`. +См. [`SETUP-RU.md`](https://git.macaw.me/skunky/SkunkyArt/src/branch/master/SETUP-RU.md) для информации о настройки фронтенда. +## Добавление инстанса в список +Чтобы это сделать, вы должны либо сделать PR, добавив в файлы `instances.json` и `INSTANCES.md` свой инстанс (можете воспользоваться cli-аргументом `--add-instance`, который автоматически это сделает), либо создать Issue, или сообщить о нём в комнате в Matrix. Учтите, что ваш инстанс должен соблюсти следущие правила: +1. Инстанс не должен использовать Cloudflare итп. 2. Если ваш инстанс имеет модифицированный исходный код, то вам нужно опубликовать его на любую свободную площадку. Например, Github и Gitlab таковыми не являются. ## Благодарности -* [Лис⚛](https://go.kde.org/matrix/#/@fox:matrix.org) -- помог разобраться в Go и много чего полезного посоветовал по этому языку. \ No newline at end of file +* [Лис⚛](https://go.kde.org/matrix/#/@fox:matrix.org) — помог разобраться в Go и много чего полезного посоветовал по этому языку. +* [meoww](https://codeberg.org/meoww) — перевела некоторые предложения на английский язык и написала сервис для openrc \ No newline at end of file diff --git a/SETUP-RU.md b/SETUP-RU.md new file mode 100644 index 0000000..6ff3c23 --- /dev/null +++ b/SETUP-RU.md @@ -0,0 +1,42 @@ +[English version 🇬🇧](https://git.macaw.me/skunky/SkunkyArt/src/branch/master/SETUP.md) + +# Единицы измерения +Размер файла в кеше измеряется в мегабайтах.
+Единицы времени: +* `i` — минуты +* `h` — часы +* `w` — недели +* `m` — месяца +* `y` — года + +# Конфигурация +* `listen` — IP и порт для слушанья; заполняется по такой форме: ip:port +* `uri` — URI инстанса. Пример: `"uri":"/art/"` -> https://skunky.ebloid.ru/art/ +* `cache` — Система кеширования; по умолчанию выключена. + * `enabled` — Состояние системы кеширования; требуется булёвое значение + * `path` — Полный путь до каталога, куда будет сохраняться кеш + * `lifetime` — Время жизни файла в кеше, требует целочисленное значение, дополненное суффиксом времени (см. 'Единицы времени') + * `max-size` — Максимальный размер файла + * `update-interval` — Интервал для автоматической ротации кеша +* `dirs-to-memory` — Массив, заполнив который скопируются все файлы из указанных каталогов +* `download-proxy` — Адрес прокси для загрузки файлов +* `user-agent` — Строка, которая используется в качестве User-Agent'а + +# Настройка обратного прокси +Если вы собираетесь хостить инстанс в Интернете, то вам следует настроить заголовок прокси [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto). В противном случае, все ссылки на вашем инстансе будут вида "http". Ниже есть информация о том, как настроить обратное проксирование: + +Nginx: +```apache +server { + listen 443 ssl; + server_name skunky.example.com; + + # Если используется поддомен, то вместо ((BASE_URL)), укажите '/'. + location ((BASE_URL)) { + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + proxy_http_version 1.1; + proxy_pass http://((IP)):((PORT)); + } +} +``` \ No newline at end of file diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..ab30165 --- /dev/null +++ b/SETUP.md @@ -0,0 +1,42 @@ +[Версия на русском языке 🇷🇺](https://git.macaw.me/skunky/SkunkyArt/src/branch/master/SETUP-RU.md) + +# Units +Maximum file size in megabytes, requires numeric value.
+Time units: +* `i` — minutes +* `h` — hours +* `w` — weeks +* `m` — months +* `y` — years + +# Config +* `listen` — IP and port to listen on in the following form: ip:port +* `uri` — Instance URI. Example: `"uri":"/art/"` -> https://skunky.ebloid.ru/art/ +* `cache` — Caching system; default is off. + * `enabled` — Caching system state, requires boolean value + * `path` — Path to cache directory, requires absolute filesystem path + * `lifetime` — Cached file life time, requires numeric value, followed by multiplicative suffix (see Time Units for details) + * `max-size` — Maximum file size in megabytes + * `update-interval` — Automatic rotation interval +* `dirs-to-memory` — This setting determines which directories will be copied to RAM when SkunkyArt is started. Mandatory +* `download-proxy` — Proxy address for downloading files. +* `user-agent` — String, which SkunkyArt uses as UA + +# Setting up reverse proxy +Pretty much business as usual, except for the [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) header setting. + +Nginx example configuration: +```apache +server { + listen 443 ssl; + server_name skunky.example.com; + + # In case of subdomain, use / instend of ((BASE_URL)) + location ((BASE_URL)) { + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + proxy_http_version 1.1; + proxy_pass http://((IP)):((PORT)); + } +} +``` \ No newline at end of file diff --git a/TODO.md b/TODO.md index cdb4c95..ee50111 100644 --- a/TODO.md +++ b/TODO.md @@ -1,14 +1,17 @@ # v1.3.x -* Написать Makefile * Почистить говнокод * **Доделать парсинг описания** * Избавиться от хардкода под Linux * ~~Реализовать стрипы в ежедневных артах~~ +* Сделать нормальное отображение ошибок * ~~Исправить баг с навигацией по страницам~~ * ~~Сделать единицы в конфиге более понятными~~ * Добавить возможность включить темплейты в бинарник * ~~Реализовать миниатюры и оптимизировать CSS под маленькие экраны~~ +* Написать Makefile и скрипт для автоматического развёртывания инстанса * **Реализовать отображение контента, отличного от картинок (видео, аудио, etc)** +* Исправить баг с эмоджи, когда некоторые кастомные эмоции могут не отображаться +* Добавить флаг сборки, который позволит собрать бинарник со встроенными темплейтами * Улучшить систему кеширования: добавить рейтинг для удаления и копирование изображений в ОЗУ # v1.4 * Реализовать API diff --git a/app/cli.go b/app/cli.go new file mode 100644 index 0000000..4d4f849 --- /dev/null +++ b/app/cli.go @@ -0,0 +1,166 @@ +package app + +import ( + "bufio" + "bytes" + "encoding/json" + "os" + "time" +) + +func ExecuteCommandLineArguments() { + const helpmsg = `SkunkyArt v1.3.1 [CSS improvements for mobile and the strips on Daily Deviations] +Usage: + - [-c|--config] | path to config + - [-a|--add-instance] | generates 'instances.json' and 'INSTANCES.md' files with ur instance + - [-h|--help] | returns this message +Example: + ./skunkyart -c config.json +Copyright lost+skunk, X11. https://git.macaw.me/skunky/skunkyart/src/tag/v1.3.1` + + a := os.Args[1:] + for n, x := range a { + switch x { + case "-c", "--config": + if len(a) >= 2 { + CFG.cfg = a[n+1] + } else { + exit("Not enought arguments", 1) + } + case "-h", "--help": + exit(helpmsg, 0) + case "-a", "--add-instance": + addInstance() + } + } +} + +type settingsUrls struct { + I2P string `json:"i2p,omitempty"` + Ygg string `json:"ygg,omitempty"` + Tor string `json:"tor,omitempty"` + Clearnet string `json:"clearnet,omitempty"` +} + +type settingsParams struct { + Nsfw bool `json:"nsfw"` + Proxy bool `json:"proxy"` +} + +type settings struct { + Title string `json:"title"` + Country string `json:"country"` + ModifiedSrc string `json:"modified-src,omitempty"` + Urls settingsUrls `json:"urls"` + Settings settingsParams `json:"settings"` +} + +func addInstance() { + prompt := func(txt string, necessary bool) string { + input := bufio.NewScanner(os.Stdin) + for { + print(txt) + print(": ") + input.Scan() + + if i := input.Text(); necessary && i == "" { + println("Please specify the", txt) + } else { + return i + } + } + } + + var settingsVar struct { + Instances []settings `json:"instances"` + } + instancesJson, err := os.OpenFile("instances.test.json", os.O_CREATE|os.O_WRONLY, 0644) + try(err) + defer instancesJson.Close() + + instances, err := os.OpenFile("INSTANCES.md", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + try(err) + defer instances.Close() + + for { + if Templates["instances.json"] == "" { + print("\rDownloading instance list...") + } else { + println("\r\033[2KDownloaded!") + try(json.Unmarshal([]byte(Templates["instances.json"]), &settingsVar)) + + settingsVar.Instances = append(settingsVar.Instances, settings{ + Title: prompt("Title", true), + Country: prompt("Country", true), + ModifiedSrc: prompt("Link to modified sources", false), + Settings: settingsParams{ + Nsfw: CFG.Nsfw, + Proxy: CFG.Proxy, + }, + Urls: settingsUrls{ + Clearnet: prompt("Clearnet link", false), + Ygg: prompt("Yggdrasil link", false), + Tor: prompt("Onion link", false), + I2P: prompt("I2P link", false), + }, + }) + + j, err := json.MarshalIndent(&settingsVar, "", " ") + try(err) + + instancesJson.Write(j) + + settingsVar := &settingsVar.Instances[len(settingsVar.Instances)-1] + var mdstr bytes.Buffer + + mdstr.WriteString("\n|") + if settingsVar.Urls.Clearnet != "" { + mdstr.WriteString("[") + mdstr.WriteString(settingsVar.Title) + mdstr.WriteString("](") + mdstr.WriteString(settingsVar.Urls.Clearnet) + mdstr.WriteString(")") + } else { + mdstr.WriteString(settingsVar.Title) + } + mdstr.WriteString("|") + + urls := []string{settingsVar.Urls.Ygg, settingsVar.Urls.I2P, settingsVar.Urls.Tor} + for i, l := 0, len(urls); i < l; i++ { + url := urls[i] + if url != "" { + mdstr.WriteString("[Yes](") + mdstr.WriteString(url) + mdstr.WriteString(")|") + } else { + mdstr.WriteString("No|") + } + } + + settings := []bool{settingsVar.Settings.Nsfw, settingsVar.Settings.Proxy} + for i, l := 0, len(settings); i < l; i++ { + if settings[i] { + mdstr.WriteString("Yes|") + } else { + mdstr.WriteString("No|") + } + } + + if settingsVar.ModifiedSrc != "" { + mdstr.WriteString("[Yes](") + mdstr.WriteString(settingsVar.ModifiedSrc) + mdstr.WriteString(")|") + } else { + mdstr.WriteString("No|") + } + + mdstr.WriteString(settingsVar.Country) + mdstr.WriteString("|") + + instances.Write(mdstr.Bytes()) + break + } + time.Sleep(500 * time.Millisecond) + } + exit("Done! Now add the files 'instances.json' and 'INSTANCES.md' to the 'master' branch in the repository https://git.macaw.me/skunky/SkunkyArt", 0) +} diff --git a/app/config.go b/app/config.go index 3fb8103..a6ac756 100644 --- a/app/config.go +++ b/app/config.go @@ -21,7 +21,7 @@ type cache_config struct { type config struct { cfg string Listen string - BasePath string `json:"base-path"` + URI string `json:"uri"` Cache cache_config Proxy, Nsfw bool UserAgent string `json:"user-agent"` @@ -30,15 +30,15 @@ type config struct { } var CFG = config{ - cfg: "config.json", - Listen: "127.0.0.1:3003", - BasePath: "/", + cfg: "config.json", + Listen: "127.0.0.1:3003", + URI: "/", Cache: cache_config{ - Enabled: true, + Enabled: false, Path: "cache", UpdateInterval: 1, }, - Dirs: []string{"html", "css"}, + Dirs: []string{"html", "css", "misc"}, UserAgent: "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, Nsfw: true, @@ -47,42 +47,6 @@ var CFG = config{ var lifetimeParsed int64 func ExecuteConfig() { - go func() { - for { - func() { - defer func() { - if r := recover(); r != nil { - recover() - } - }() - Templates["instances.json"] = string(Download("https://git.macaw.me/skunky/SkunkyArt/raw/branch/master/instances.json").Body) - }() - time.Sleep(1 * time.Hour) - } - }() - - const helpmsg = `SkunkyArt v1.3.1 [CSS improvements for mobile and strips on Daily Deviations] -Usage: - - [-c|--config] - path to config - - [-h|--help] - returns this message -Example: - ./skunkyart -c config.json -Copyright lost+skunk, X11. https://git.macaw.me/skunky/skunkyart/src/tag/v1.3.1` - - a := os.Args - for n, x := range a { - switch x { - case "-c", "--config": - if len(a) >= 3 { - CFG.cfg = a[n+1] - } else { - exit("Not enought arguments", 1) - } - case "-h", "--help": - exit(helpmsg, 0) - } - } - if CFG.cfg != "" { f, err := os.ReadFile(CFG.cfg) tryWithExitStatus(err, 1) diff --git a/app/router.go b/app/router.go index 33c3189..f87aa50 100644 --- a/app/router.go +++ b/app/router.go @@ -11,7 +11,7 @@ var Host string func Router() { parsepath := func(path string) map[int]string { - if l := len(CFG.BasePath); len(path) > l { + if l := len(CFG.URI); len(path) > l { path = path[l-1:] } else { path = "/" @@ -54,7 +54,7 @@ func Router() { var skunky skunkyart skunky.Writer = w skunky.Args = r.URL.Query() - skunky.BasePath = CFG.BasePath + skunky.BasePath = CFG.URI arg := skunky.Args.Get skunky.QueryRaw = arg("q") @@ -75,7 +75,7 @@ func Router() { default: skunky.ReturnHTTPError(404) case "": - skunky.ExecuteTemplate("index.htm", &CFG.BasePath) + skunky.ExecuteTemplate("index.htm", &CFG.URI) case "post": skunky.Deviation(path[2], path[3]) case "search": diff --git a/app/util.go b/app/util.go index 11f81a1..8c26760 100644 --- a/app/util.go +++ b/app/util.go @@ -32,6 +32,20 @@ func tryWithExitStatus(err error, code int) { } } +func RefreshInstances() { + for { + func() { + defer func() { + if r := recover(); r != nil { + recover() + } + }() + Templates["instances.json"] = string(Download("https://git.macaw.me/skunky/SkunkyArt/raw/branch/master/instances.json").Body) + }() + time.Sleep(1 * time.Hour) + } +} + // some crap for frontend func (s skunkyart) ExecuteTemplate(file string, data any) { var buf strings.Builder @@ -46,7 +60,7 @@ func UrlBuilder(strs ...string) string { var str strings.Builder l := len(strs) str.WriteString(Host) - str.WriteString(CFG.BasePath) + str.WriteString(CFG.URI) for n, x := range strs { str.WriteString(x) if n+1 < l && !(strs[n+1][0] == '?' || strs[n+1][0] == '&') && !(x[0] == '?' || x[0] == '&') { @@ -220,11 +234,10 @@ func BuildUserPlate(name string) string { func GetValueOfTag(t *html.Tokenizer) string { for tt := t.Next(); ; { - switch tt { - default: - return "" - case html.TextToken: + if tt == html.TextToken { return string(t.Text()) + } else { + return "" } } } diff --git a/app/wrapper.go b/app/wrapper.go index 51d76a9..250e88b 100644 --- a/app/wrapper.go +++ b/app/wrapper.go @@ -31,20 +31,7 @@ type skunkyart struct { About struct { Proxy bool Nsfw bool - Instances []struct { - Title string - Country string - Urls []struct { - I2P string `json:"i2p"` - Ygg string - Tor string - Clearnet string - } - Settings struct { - Nsfw bool - Proxy bool - } - } + Instances []settings } SomeList string @@ -229,48 +216,49 @@ func (s skunkyart) GRUser() { // посты func (s skunkyart) Deviation(author, postname string) { id_search := regexp.MustCompile("[0-9]+").FindAllString(postname, -1) - if len(id_search) >= 1 { - post := &s.Templates.Deviation - - id := id_search[len(id_search)-1] - post.Post = devianter.GetDeviation(id, author) - - if post.Post.Deviation.TextContent.Excerpt != "" { - post.Post.Description = ParseDescription(post.Post.Deviation.TextContent) - } else { - post.Post.Description = ParseDescription(post.Post.Deviation.Extended.DescriptionText) - } - // время публикации - post.StringTime = post.Post.Deviation.PublishedTime.UTC().String() - post.Post.IMG = ParseMedia(post.Post.Deviation.Media) - for _, x := range post.Post.Deviation.Extended.RelatedContent { - if len(x.Deviations) != 0 { - post.Related += s.DeviationList(x.Deviations, false) - } - } - - // хештэги - for _, x := range post.Post.Deviation.Extended.Tags { - var tag strings.Builder - tag.WriteString(` #`) - tag.WriteString(x.Name) - tag.WriteString("") - - post.Tags += tag.String() - } - - if post.Post.Comments.Total <= 50 { - post.Post.Comments.Cursor = "" - } - - post.Comments = s.ParseComments(devianter.GetComments(id, post.Post.Comments.Cursor, s.Page, 1)) - - s.ExecuteTemplate("deviantion.htm", &s) - } else { + if len(id_search) < 1 { s.ReturnHTTPError(400) + return } + + post := &s.Templates.Deviation + + id := id_search[len(id_search)-1] + post.Post = devianter.GetDeviation(id, author) + + if post.Post.Deviation.TextContent.Excerpt != "" { + post.Post.Description = ParseDescription(post.Post.Deviation.TextContent) + } else { + post.Post.Description = ParseDescription(post.Post.Deviation.Extended.DescriptionText) + } + // время публикации + post.StringTime = post.Post.Deviation.PublishedTime.UTC().String() + post.Post.IMG = ParseMedia(post.Post.Deviation.Media) + for _, x := range post.Post.Deviation.Extended.RelatedContent { + if len(x.Deviations) != 0 { + post.Related += s.DeviationList(x.Deviations, false) + } + } + + // хештэги + for _, x := range post.Post.Deviation.Extended.Tags { + var tag strings.Builder + tag.WriteString(` #`) + tag.WriteString(x.Name) + tag.WriteString("") + + post.Tags += tag.String() + } + + if post.Post.Comments.Total <= 50 { + post.Post.Comments.Cursor = "" + } + + post.Comments = s.ParseComments(devianter.GetComments(id, post.Post.Comments.Cursor, s.Page, 1)) + + s.ExecuteTemplate("deviantion.htm", &s) } func (s skunkyart) DD() { @@ -298,7 +286,6 @@ func (s skunkyart) DD() { } func (s skunkyart) Search() { - s.Atom = false var err error ss := &s.Templates.Search switch s.Type { @@ -365,15 +352,16 @@ func (s skunkyart) Search() { } func (s skunkyart) Emojitar(name string) { - if name != "" && (s.Type == 'a' || s.Type == 'e') { - ae, e := devianter.AEmedia(name, s.Type) - if e != nil { - s.ReturnHTTPError(404) - } - wr(s.Writer, ae) - } else { + if name == "" || !(s.Type == 'a' || s.Type == 'e') { s.ReturnHTTPError(400) + return } + + ae, e := devianter.AEmedia(name, s.Type) + if e != nil { + s.ReturnHTTPError(404) + } + wr(s.Writer, ae) } func (s skunkyart) About() { diff --git a/config.example.json b/config.example.json index b4d1ce2..0934fe7 100644 --- a/config.example.json +++ b/config.example.json @@ -1,17 +1,17 @@ { - "listen": "0.0.0.0:3003", - "base-path": "/", + "listen": "0:3003", + "uri": "/", "cache": { "enabled": true, - "path": "/home/skunk/projects/skunkyart/cache", - "lifetime": "1w", + "path": "cache", + "lifetime": null, "max-size": 1024, "update-interval": 5 }, "dirs-to-memory": [ - "/home/skunk/projects/skunkyart/html", - "/home/skunk/projects/skunkyart/css", - "/home/skunk/projects/skunkyart/misc" + "html", + "css", + "misc" ], "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", diff --git a/go.mod b/go.mod index 7e5e771..8016fa3 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,7 @@ module skunkyart go 1.22.3 -replace git.macaw.me/skunky/devianter v0.2.0 => /home/skunk/projects/devianter - require ( - git.macaw.me/skunky/devianter v0.2.0 + git.macaw.me/skunky/devianter v0.2.5 golang.org/x/net v0.27.0 ) diff --git a/go.sum b/go.sum index 59de12e..8e79784 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -git.macaw.me/skunky/devianter v0.2.0 h1:2vnMPb1Dax37CbAOfmHcSoK8+1goFkWHbtbh31Ytsww= -git.macaw.me/skunky/devianter v0.2.0/go.mod h1:ZLn527xBlnpXrUB1B8z/MhyeiWVK4nPWjyfnhWOE8Is= +git.macaw.me/skunky/devianter v0.2.5 h1:aAc6CG/ghvG130Ob7gGUdK4IV3MSeCD5t3QIJjto1M0= +git.macaw.me/skunky/devianter v0.2.5/go.mod h1:ZLn527xBlnpXrUB1B8z/MhyeiWVK4nPWjyfnhWOE8Is= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= diff --git a/html/about.htm b/html/about.htm index 31f58c8..edb576d 100644 --- a/html/about.htm +++ b/html/about.htm @@ -3,6 +3,7 @@ SkunkyArt +
@@ -21,43 +22,43 @@ SkunkyArt is an alternative frontend for deviantart.com, written in Go.

Room in Matrix

-

Instance settings:

+ Instance settings:
  • NSFW: {{if .Templates.About.Nsfw}}YES{{else}}NO{{end}}
  • Proxyfing: {{if .Templates.About.Proxy}}YES{{else}}NO{{end}}
-

Instances:

-
    - {{range .Templates.About.Instances}} -
  • {{.Title}}: -
      -
    • Country: {{.Country}}
    • -
    • URLs:
    • +
      + Instances: +
        + {{range .Templates.About.Instances}} +
      • {{.Title}}:
          - {{range .Urls}} - {{if ne .I2P ""}} -
        • I2P: Yes
        • - {{end}} - {{if ne .Ygg ""}} -
        • Ygg: Yes
        • - {{end}} - {{if ne .Tor ""}} -
        • Tor: Yes
        • - {{end}} - {{if ne .Clearnet ""}} -
        • Clearnet: {{.Clearnet}}
        • - {{end}} - {{end}} +
        • Country: {{.Country}}
        • +
        • URLs:
        • +
            + {{if ne .Urls.I2P ""}} +
          • I2P: Yes
          • + {{end}} + {{if ne .Urls.Ygg ""}} +
          • Ygg: Yes
          • + {{end}} + {{if ne .Urls.Tor ""}} +
          • Tor: Yes
          • + {{end}} + {{if ne .Urls.Clearnet ""}} +
          • Clearnet: {{.Urls.Clearnet}}
          • + {{end}} +
          +
        • Settings:
        • +
            +
          • NSFW: {{if .Settings.Nsfw}}YES{{else}}NO{{end}}
          • +
          • Proxyfing: {{if .Settings.Proxy}}YES{{else}}NO{{end}}
          • +
        -
      • Settings:
      • -
          -
        • NSFW: {{if .Settings.Nsfw}}YES{{else}}NO{{end}}
        • -
        • Proxyfing: {{if .Settings.Proxy}}YES{{else}}NO{{end}}
        • -
        -
      - - {{end}} -
    +
  • + {{end}} +
+

Copyright lost+skunk, X11. SkunkyArt v1.3.1

\ No newline at end of file diff --git a/html/daily.htm b/html/daily.htm index 22e9275..c464268 100644 --- a/html/daily.htm +++ b/html/daily.htm @@ -3,6 +3,7 @@ SkunkyArt | Daily Deviations +
diff --git a/html/deviantion.htm b/html/deviantion.htm index c00c1ae..50710b6 100644 --- a/html/deviantion.htm +++ b/html/deviantion.htm @@ -4,6 +4,7 @@ SkunkyArt | {{.Templates.Deviation.Post.Deviation.Author.Username}} - {{.Templates.Deviation.Post.Deviation.Title}} +
diff --git a/html/gruser.htm b/html/gruser.htm index ee7de73..a219e36 100644 --- a/html/gruser.htm +++ b/html/gruser.htm @@ -9,6 +9,7 @@ {{end}} +
diff --git a/html/index.htm b/html/index.htm index 3347306..08feba5 100644 --- a/html/index.htm +++ b/html/index.htm @@ -3,6 +3,7 @@ SkunkyArt +
diff --git a/html/search.htm b/html/search.htm index fee5ada..df1cf85 100644 --- a/html/search.htm +++ b/html/search.htm @@ -3,6 +3,7 @@ SkunkyArt | Search "{{.QueryRaw}}" +
diff --git a/instances.json b/instances.json index eeb329a..cd95b78 100644 --- a/instances.json +++ b/instances.json @@ -3,10 +3,10 @@ { "title": "skunky.ebloid.ru", "country": "Russia", - "urls": [{ + "urls": { "ygg": "http://[201:eba5:d1fc:bf7b:cfcb:a811:4b8b:7ea3]/art", "clearnet": "https://skunky.ebloid.ru/art" - }], + }, "settings": { "nsfw": false, "proxy": false @@ -15,9 +15,9 @@ { "title": "clovius.club", "country": "Sweden", - "urls": [{ + "urls": { "clearnet": "https://skunky.clovius.club" - }], + }, "settings": { "nsfw": true, "proxy": true @@ -26,9 +26,9 @@ { "title": "bloat.cat", "country": "Romania", - "urls": [{ + "urls": { "clearnet": "https://skunky.bloat.cat" - }], + }, "settings": { "nsfw": true, "proxy": true @@ -37,9 +37,9 @@ { "title": "frontendfriendly.xyz", "country": "Finland", - "urls": [{ + "urls": { "clearnet": "https://skunkyart.frontendfriendly.xyz" - }], + }, "settings": { "nsfw": true, "proxy": true @@ -48,9 +48,9 @@ { "title": "lumaeris.com", "country": "US", - "urls": [{ + "urls": { "clearnet": "https://skunkyart.lumaeris.com" - }], + }, "settings": { "nsfw": true, "proxy": true diff --git a/main.go b/main.go index 43b95f0..0224816 100644 --- a/main.go +++ b/main.go @@ -2,17 +2,27 @@ package main import ( "skunkyart/app" + "time" "git.macaw.me/skunky/devianter" ) func main() { + go app.RefreshInstances() + + app.ExecuteCommandLineArguments() app.ExecuteConfig() app.CopyTemplatesToMemory() - err := devianter.UpdateCSRF() - if err != nil { - println(err.Error()) - } + + go func() { + for { + err := devianter.UpdateCSRF() + if err != nil { + println(err.Error()) + } + time.Sleep(12 * time.Hour) + } + }() app.Router() } diff --git a/services/skunkyart.example.openrc b/services/skunkyart.example.openrc index d89d5b2..9309251 100755 --- a/services/skunkyart.example.openrc +++ b/services/skunkyart.example.openrc @@ -1,13 +1,20 @@ #!/sbin/openrc-run - -directory= -# command_args="-c $directory/config.json" # if SA wasn't start, try to uncomment this line -command=$directory/skunkyart - -name="SkunkyArt" -description="Privacy frontend for deviantart.com" supervisor=supervise-daemon +user=skunkyart:skunkyart +name=SkunkyArt +directory=/opt/skunkyart +command=$directory/bin/skunkyart +description="Privacy-oriented frontend for DeviantArt" +error_logger=logger +output_logger=logger +no_new_privs=true +umask=0077 + +# if you use old version openrc, uncomment function lower +# start_pre() { +# cd $directory +# } depend() { - need net + need net localmount bootmisc } \ No newline at end of file diff --git a/services/skunkyart.example.service b/services/skunkyart.example.service index 6531cab..2699d83 100644 --- a/services/skunkyart.example.service +++ b/services/skunkyart.example.service @@ -1,7 +1,7 @@ # Note: i didn't use systemd, so it can be not works :) [Unit] -Description=Privacy frontend for deviantart.com +Description=Privacy-oriented frontend for DeviantArt [Service] Directory=