Реализация конфига
This commit is contained in:
parent
8b839f9406
commit
7f1ab1b73d
@ -1,26 +1,31 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cache_config struct {
|
type cache_config struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Path string
|
Path string
|
||||||
Max_size, Lifetime int64
|
MaxSize int64 `json:"max-size"`
|
||||||
|
Lifetime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
cfg string
|
cfg string
|
||||||
Listen, Base_uri string
|
Listen string
|
||||||
Cache cache_config
|
BasePath string `json:"base-path"`
|
||||||
Proxy, Nsfw bool
|
Cache cache_config
|
||||||
|
Proxy, Nsfw bool
|
||||||
|
WixmpProxy string `json:"wixmp-proxy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var CFG = config{
|
var CFG = config{
|
||||||
cfg: "config.json",
|
cfg: "config.json",
|
||||||
Listen: "127.0.0.1:3003",
|
Listen: "127.0.0.1:3003",
|
||||||
Base_uri: "/",
|
BasePath: "/",
|
||||||
Cache: cache_config{
|
Cache: cache_config{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Path: "cache",
|
Path: "cache",
|
||||||
@ -29,20 +34,46 @@ var CFG = config{
|
|||||||
Nsfw: true,
|
Nsfw: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func execcfg() {
|
func ExecuteConfig() {
|
||||||
|
try := func(err error, exitcode int) {
|
||||||
|
if err != nil {
|
||||||
|
println(err.Error())
|
||||||
|
os.Exit(exitcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a := os.Args
|
a := os.Args
|
||||||
for num, val := range a {
|
if l := len(a); l > 1 {
|
||||||
switch val {
|
switch a[1] {
|
||||||
case "-conf":
|
case "-c", "--config":
|
||||||
CFG.cfg = a[num]
|
if l >= 3 {
|
||||||
case "-help":
|
CFG.cfg = a[2]
|
||||||
println(`SkunkyArt v 1.3 [refactoring]
|
} else {
|
||||||
|
try(errors.New("Not enought arguments"), 1)
|
||||||
|
}
|
||||||
|
case "-h", "--help":
|
||||||
|
try(errors.New(`SkunkyArt v1.3 [refactoring]
|
||||||
Usage:
|
Usage:
|
||||||
- -conf - path to config
|
- [-c|--config] - path to config
|
||||||
- -help this message
|
- [-h|--help] - returns this message
|
||||||
Example:
|
Example:
|
||||||
./skunkyart -conf config.json
|
./skunkyart -c config.json
|
||||||
Copyright lost+skunk, X11. https://git.macaw.me/skunky/skunkyart/src/tag/v1.3`)
|
Copyright lost+skunk, X11. https://git.macaw.me/skunky/skunkyart/src/tag/v1.3`), 0)
|
||||||
|
default:
|
||||||
|
try(errors.New("Unreconginzed argument: "+a[1]), 1)
|
||||||
|
}
|
||||||
|
if CFG.cfg != "" {
|
||||||
|
f, err := os.ReadFile(CFG.cfg)
|
||||||
|
try(err, 1)
|
||||||
|
|
||||||
|
try(json.Unmarshal(f, &CFG), 1)
|
||||||
|
if CFG.Cache.Enabled && !CFG.Proxy {
|
||||||
|
try(errors.New("Incompatible settings detected: cannot use caching media content without proxy"), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if CFG.Cache.MaxSize != 0 || CFG.Cache.Lifetime != 0 {
|
||||||
|
go InitCacheSystem()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const addr string = "0.0.0.0:3003"
|
|
||||||
|
|
||||||
// роутер
|
|
||||||
func Router() {
|
func Router() {
|
||||||
parsepath := func(path string) map[int]string {
|
parsepath := func(path string) map[int]string {
|
||||||
|
if l := len(CFG.BasePath); len(path) > l {
|
||||||
|
path = path[l-1:]
|
||||||
|
} else {
|
||||||
|
path = "/"
|
||||||
|
}
|
||||||
|
|
||||||
parsedpath := make(map[int]string)
|
parsedpath := make(map[int]string)
|
||||||
for x := 0; true; x++ {
|
for x := 0; true; x++ {
|
||||||
slash := strings.Index(path, "/") + 1
|
slash := strings.Index(path, "/") + 1
|
||||||
@ -52,16 +55,20 @@ func Router() {
|
|||||||
var skunky skunkyart
|
var skunky skunkyart
|
||||||
skunky.Args = r.URL.Query()
|
skunky.Args = r.URL.Query()
|
||||||
skunky.Writer = w
|
skunky.Writer = w
|
||||||
|
skunky.BasePath = CFG.BasePath
|
||||||
|
|
||||||
arg := skunky.Args.Get
|
arg := skunky.Args.Get
|
||||||
skunky.Query = u.QueryEscape(arg("q"))
|
skunky.QueryRaw = arg("q")
|
||||||
|
skunky.Query = u.QueryEscape(skunky.QueryRaw)
|
||||||
|
|
||||||
if t := arg("type"); len(t) > 0 {
|
if t := arg("type"); len(t) > 0 {
|
||||||
skunky.Type = rune(t[0])
|
skunky.Type = rune(t[0])
|
||||||
}
|
}
|
||||||
p, _ := strconv.Atoi(arg("p"))
|
p, _ := strconv.Atoi(arg("p"))
|
||||||
skunky.Page = p
|
skunky.Page = p
|
||||||
|
|
||||||
if arg("atom") == "true" {
|
if arg("atom") == "true" {
|
||||||
skunky.atom = true
|
skunky.Atom = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// пути
|
// пути
|
||||||
@ -69,7 +76,7 @@ func Router() {
|
|||||||
default:
|
default:
|
||||||
skunky.ReturnHTTPError(404)
|
skunky.ReturnHTTPError(404)
|
||||||
case "":
|
case "":
|
||||||
open_n_send("html/index.htm")
|
skunky.ExecuteTemplate("html/index.htm", &CFG.BasePath)
|
||||||
case "post":
|
case "post":
|
||||||
skunky.Deviation(path[2], path[3])
|
skunky.Deviation(path[2], path[3])
|
||||||
case "search":
|
case "search":
|
||||||
@ -80,9 +87,14 @@ func Router() {
|
|||||||
skunky.GRUser()
|
skunky.GRUser()
|
||||||
|
|
||||||
case "media":
|
case "media":
|
||||||
skunky.Emojitar(path[2])
|
switch path[2] {
|
||||||
|
case "file":
|
||||||
|
skunky.DownloadAndSendMedia(path[3], next(path, 4))
|
||||||
|
case "emojitar":
|
||||||
|
skunky.Emojitar(path[3])
|
||||||
|
}
|
||||||
case "about":
|
case "about":
|
||||||
open_n_send("html/about.htm")
|
skunky.About()
|
||||||
case "gui":
|
case "gui":
|
||||||
w.Header().Add("content-type", "text/css")
|
w.Header().Add("content-type", "text/css")
|
||||||
open_n_send(next(path, 2))
|
open_n_send(next(path, 2))
|
||||||
@ -90,7 +102,7 @@ func Router() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
http.HandleFunc("/", handle)
|
http.HandleFunc("/", handle)
|
||||||
http.ListenAndServe(addr, nil)
|
http.ListenAndServe(CFG.Listen, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func err(e error) {
|
func err(e error) {
|
||||||
|
257
app/util.go
257
app/util.go
@ -1,11 +1,17 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
u "net/url"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.macaw.me/skunky/devianter"
|
"git.macaw.me/skunky/devianter"
|
||||||
)
|
)
|
||||||
@ -19,11 +25,15 @@ func (s skunkyart) ExecuteTemplate(file string, data any) {
|
|||||||
wr(s.Writer, buf.String())
|
wr(s.Writer, buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s skunkyart) UrlBuilder(strs ...string) string {
|
func UrlBuilder(strs ...string) string {
|
||||||
var str strings.Builder
|
var str strings.Builder
|
||||||
for _, x := range strs {
|
l := len(strs)
|
||||||
|
str.WriteString(CFG.BasePath)
|
||||||
|
for n, x := range strs {
|
||||||
str.WriteString(x)
|
str.WriteString(x)
|
||||||
str.WriteString("/")
|
if n+1 < l && !(strs[n+1][0] == '?' || strs[n+1][0] == '&') && !(x[0] == '?' || x[0] == '&') {
|
||||||
|
str.WriteString("/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return str.String()
|
return str.String()
|
||||||
}
|
}
|
||||||
@ -31,10 +41,10 @@ func (s skunkyart) UrlBuilder(strs ...string) string {
|
|||||||
func (s skunkyart) ReturnHTTPError(status int) {
|
func (s skunkyart) ReturnHTTPError(status int) {
|
||||||
s.Writer.WriteHeader(status)
|
s.Writer.WriteHeader(status)
|
||||||
|
|
||||||
// пострйока с помощью strings.Builder, потому что такой метод быстрее обычного сложения
|
|
||||||
var msg strings.Builder
|
var msg strings.Builder
|
||||||
msg.WriteString(`<html><link rel="stylesheet" href="/gui/css/skunky.css" />`)
|
msg.WriteString(`<html><link rel="stylesheet" href="`)
|
||||||
msg.WriteString("<h1>")
|
msg.WriteString(UrlBuilder("gui", "css", "skunky.css"))
|
||||||
|
msg.WriteString(`" /><h1>`)
|
||||||
msg.WriteString(strconv.Itoa(status))
|
msg.WriteString(strconv.Itoa(status))
|
||||||
msg.WriteString(" - ")
|
msg.WriteString(" - ")
|
||||||
msg.WriteString(http.StatusText(status))
|
msg.WriteString(http.StatusText(status))
|
||||||
@ -43,6 +53,15 @@ func (s skunkyart) ReturnHTTPError(status int) {
|
|||||||
wr(s.Writer, msg.String())
|
wr(s.Writer, msg.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s skunkyart) ConvertDeviantArtUrlToSkunkyArt(url string) (output string) {
|
||||||
|
if len(url) > 32 && url[27:32] != "stash" {
|
||||||
|
url = url[27:]
|
||||||
|
toart := strings.Index(url, "/art/")
|
||||||
|
output = UrlBuilder("post", url[:toart], url[toart+5:])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type text struct {
|
type text struct {
|
||||||
TXT string
|
TXT string
|
||||||
from int
|
from int
|
||||||
@ -200,80 +219,78 @@ func (s skunkyart) NavBase(c dlist) string {
|
|||||||
|
|
||||||
func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) string {
|
func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) string {
|
||||||
var list strings.Builder
|
var list strings.Builder
|
||||||
if !s.atom {
|
if s.Atom && s.Page > 1 {
|
||||||
list.WriteString(`<div class="content">`)
|
s.ReturnHTTPError(400)
|
||||||
} else {
|
return ""
|
||||||
list.WriteString(`<?xml version="1.0" encoding="UTF-8"?><feed xmlns:media="http://search.yahoo.com/mrss" xmlns="http://www.w3.org/2005/Atom">`)
|
} else if s.Atom {
|
||||||
|
list.WriteString(`<?xml version="1.0" encoding="UTF-8"?><feed xmlns:media="http://search.yahoo.com/mrss/" xmlns="http://www.w3.org/2005/Atom">`)
|
||||||
list.WriteString(`<title>SkunkyArt</title>`)
|
list.WriteString(`<title>SkunkyArt</title>`)
|
||||||
// list.WriteString(`<link rel="alternate" href="HOMEPAGE_URL"/><link href="FEED_URL" rel="self"/>`)
|
// list.WriteString(`<link rel="alternate" href="HOMEPAGE_URL"/><link href="FEED_URL" rel="self"/>`)
|
||||||
|
} else {
|
||||||
|
list.WriteString(`<div class="content">`)
|
||||||
}
|
}
|
||||||
for _, data := range devs {
|
for _, data := range devs {
|
||||||
url := devianter.UrlFromMedia(data.Media)
|
if !(data.NSFW && !CFG.Nsfw) {
|
||||||
if s.atom {
|
url := s.ParseMedia(data.Media)
|
||||||
id := strconv.Itoa(data.ID)
|
if s.Atom {
|
||||||
list.WriteString(`<entry><author><name>`)
|
id := strconv.Itoa(data.ID)
|
||||||
list.WriteString(data.Author.Username)
|
list.WriteString(`<entry><author><name>`)
|
||||||
list.WriteString(`</name></author><title>`)
|
list.WriteString(data.Author.Username)
|
||||||
list.WriteString(data.Title)
|
list.WriteString(`</name></author><title>`)
|
||||||
list.WriteString(`</title><link rel="alternate" type="text/html" href="`)
|
list.WriteString(data.Title)
|
||||||
list.WriteString(CFG.Base_uri)
|
list.WriteString(`</title><link rel="alternate" type="text/html" href="`)
|
||||||
list.WriteString("/post/")
|
list.WriteString(UrlBuilder("post", data.Author.Username, "atom-"+id))
|
||||||
list.WriteString(data.Author.Username)
|
list.WriteString(`"/><id>`)
|
||||||
list.WriteString("/atom-")
|
list.WriteString(id)
|
||||||
list.WriteString(id)
|
list.WriteString(`</id><published>`)
|
||||||
list.WriteString(`"/><id>`)
|
list.WriteString(data.PublishedTime.UTC().Format("Mon, 02 Jan 2006 15:04:05 -0700"))
|
||||||
list.WriteString(id)
|
list.WriteString(`</published>`)
|
||||||
list.WriteString(`</id><published>`)
|
list.WriteString(`<media:group><media:title>`)
|
||||||
list.WriteString(data.PublishedTime.UTC().Format("Mon, 02 Jan 2006 15:04:05 -0700"))
|
list.WriteString(data.Title)
|
||||||
list.WriteString(`</published>`)
|
list.WriteString(`</media:title><media:thumbinal url="`)
|
||||||
list.WriteString(`<media:group><media:title>`)
|
|
||||||
list.WriteString(data.Title)
|
|
||||||
list.WriteString(`</media:title><media:thumbinal url="`)
|
|
||||||
list.WriteString(url)
|
|
||||||
list.WriteString(`"/></media:group><content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="`)
|
|
||||||
list.WriteString(data.Url)
|
|
||||||
list.WriteString(`"><img src="`)
|
|
||||||
list.WriteString(url)
|
|
||||||
list.WriteString(`"/></a><p>`)
|
|
||||||
list.WriteString(ParseDescription(data.TextContent))
|
|
||||||
list.WriteString(`</p></div></content></entry>`)
|
|
||||||
} else {
|
|
||||||
list.WriteString(`<div class="block">`)
|
|
||||||
if url != "" {
|
|
||||||
list.WriteString(`<a title="open/download" href="`)
|
|
||||||
list.WriteString(url)
|
list.WriteString(url)
|
||||||
|
list.WriteString(`"/></media:group><content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="`)
|
||||||
|
list.WriteString(data.Url)
|
||||||
list.WriteString(`"><img src="`)
|
list.WriteString(`"><img src="`)
|
||||||
list.WriteString(url)
|
list.WriteString(url)
|
||||||
list.WriteString(`" width="15%"></a>`)
|
list.WriteString(`"/></a><p>`)
|
||||||
|
list.WriteString(ParseDescription(data.TextContent))
|
||||||
|
list.WriteString(`</p></div></content></entry>`)
|
||||||
} else {
|
} else {
|
||||||
list.WriteString(`<h1>[ TEXT ]</h1>`)
|
list.WriteString(`<div class="block">`)
|
||||||
}
|
if url != "" {
|
||||||
list.WriteString(`<br><a href="`)
|
list.WriteString(`<a title="open/download" href="`)
|
||||||
list.WriteString("/post/")
|
list.WriteString(url)
|
||||||
list.WriteString(data.Author.Username)
|
list.WriteString(`"><img src="`)
|
||||||
list.WriteString("/")
|
list.WriteString(url)
|
||||||
list.WriteString(data.Url[27:][strings.Index(data.Url[27:], "/art/")+5:])
|
list.WriteString(`" width="15%"></a>`)
|
||||||
list.WriteString(`">`)
|
} else {
|
||||||
list.WriteString(data.Author.Username)
|
list.WriteString(`<h1>[ TEXT ]</h1>`)
|
||||||
list.WriteString(" - ")
|
}
|
||||||
list.WriteString(data.Title)
|
list.WriteString(`<br><a href="`)
|
||||||
|
list.WriteString(s.ConvertDeviantArtUrlToSkunkyArt(data.Url))
|
||||||
|
list.WriteString(`">`)
|
||||||
|
list.WriteString(data.Author.Username)
|
||||||
|
list.WriteString(" - ")
|
||||||
|
list.WriteString(data.Title)
|
||||||
|
|
||||||
// шильдики нсфв, аи и ежедневного поста
|
// шильдики нсфв, аи и ежедневного поста
|
||||||
if data.NSFW {
|
if data.NSFW {
|
||||||
list.WriteString(` [<span class="nsfw">NSFW</span>]`)
|
list.WriteString(` [<span class="nsfw">NSFW</span>]`)
|
||||||
}
|
}
|
||||||
if data.AI {
|
if data.AI {
|
||||||
list.WriteString(" [🤖]")
|
list.WriteString(" [🤖]")
|
||||||
}
|
}
|
||||||
if data.DD {
|
if data.DD {
|
||||||
list.WriteString(` [<span class="dd">DD</span>]`)
|
list.WriteString(` [<span class="dd">DD</span>]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
list.WriteString("</a></div>")
|
list.WriteString("</a></div>")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.atom {
|
if s.Atom {
|
||||||
list.WriteString("</feed>")
|
list.WriteString("</feed>")
|
||||||
s.Writer.Write([]byte(list.String()))
|
s.Writer.Write([]byte(list.String()))
|
||||||
return ""
|
return ""
|
||||||
@ -301,10 +318,10 @@ func (s skunkyart) ParseComments(c devianter.Comments) string {
|
|||||||
}
|
}
|
||||||
cmmts.WriteString(`"><p id="`)
|
cmmts.WriteString(`"><p id="`)
|
||||||
cmmts.WriteString(strconv.Itoa(x.ID))
|
cmmts.WriteString(strconv.Itoa(x.ID))
|
||||||
cmmts.WriteString(`"><img src="/media/`)
|
cmmts.WriteString(`"><img src="`)
|
||||||
cmmts.WriteString(x.User.Username)
|
cmmts.WriteString(UrlBuilder("media", "emojitar", x.User.Username, "?type=a"))
|
||||||
cmmts.WriteString(`?type=a" width="30px" height="30px"><a href="/group_user?type=about&q=`)
|
cmmts.WriteString(`" width="30px" height="30px"><a href="`)
|
||||||
cmmts.WriteString(x.User.Username)
|
cmmts.WriteString(UrlBuilder("group_user", "?q=", x.User.Username, "&type=a"))
|
||||||
cmmts.WriteString(`"><b`)
|
cmmts.WriteString(`"><b`)
|
||||||
cmmts.WriteString(` class="`)
|
cmmts.WriteString(` class="`)
|
||||||
if x.User.Banned {
|
if x.User.Banned {
|
||||||
@ -346,3 +363,101 @@ func (s skunkyart) ParseComments(c devianter.Comments) string {
|
|||||||
cmmts.WriteString("</details>")
|
cmmts.WriteString("</details>")
|
||||||
return cmmts.String()
|
return cmmts.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s skunkyart) ParseMedia(media devianter.Media) string {
|
||||||
|
url := devianter.UrlFromMedia(media)
|
||||||
|
if len(url) != 0 {
|
||||||
|
url = url[21:]
|
||||||
|
dot := strings.Index(url, ".")
|
||||||
|
|
||||||
|
return UrlBuilder("media", "file", url[:dot], "/", url[dot+10:])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s skunkyart) DownloadAndSendMedia(subdomain, path string) {
|
||||||
|
var url strings.Builder
|
||||||
|
url.WriteString("https://images-wixmp-")
|
||||||
|
url.WriteString(subdomain)
|
||||||
|
url.WriteString(".wixmp.com/")
|
||||||
|
url.WriteString(path)
|
||||||
|
url.WriteString("?token=")
|
||||||
|
url.WriteString(s.Args.Get("token"))
|
||||||
|
|
||||||
|
download := func() (body []byte, status int, headers http.Header) {
|
||||||
|
cli := &http.Client{}
|
||||||
|
if CFG.WixmpProxy != "" {
|
||||||
|
u, e := u.Parse(CFG.WixmpProxy)
|
||||||
|
err(e)
|
||||||
|
cli.Transport = &http.Transport{Proxy: http.ProxyURL(u)}
|
||||||
|
}
|
||||||
|
|
||||||
|
req, e := http.NewRequest("GET", url.String(), nil)
|
||||||
|
err(e)
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0.0")
|
||||||
|
|
||||||
|
resp, e := cli.Do(req)
|
||||||
|
err(e)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
b, e := io.ReadAll(resp.Body)
|
||||||
|
err(e)
|
||||||
|
return b, resp.StatusCode, resp.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
if CFG.Cache.Enabled {
|
||||||
|
os.Mkdir(CFG.Cache.Path, 0700)
|
||||||
|
fname := CFG.Cache.Path + "/" + base64.StdEncoding.EncodeToString([]byte(subdomain+path))
|
||||||
|
file, e := os.Open(fname)
|
||||||
|
|
||||||
|
if e != nil {
|
||||||
|
b, status, headers := download()
|
||||||
|
if status == 200 && headers["Content-Type"][0][:5] == "image" {
|
||||||
|
err(os.WriteFile(fname, b, 0700))
|
||||||
|
s.Writer.Write(b)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file, e := io.ReadAll(file)
|
||||||
|
err(e)
|
||||||
|
s.Writer.Write(file)
|
||||||
|
}
|
||||||
|
} else if CFG.Proxy {
|
||||||
|
b, _, _ := download()
|
||||||
|
s.Writer.Write(b)
|
||||||
|
} else {
|
||||||
|
s.Writer.Write([]byte("Sorry, butt proxy on this instance disabled."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitCacheSystem() {
|
||||||
|
c := &CFG.Cache
|
||||||
|
for {
|
||||||
|
dir, e := os.Open(c.Path)
|
||||||
|
err(e)
|
||||||
|
stat, e := dir.Stat()
|
||||||
|
err(e)
|
||||||
|
|
||||||
|
dirnames, e := dir.Readdirnames(-1)
|
||||||
|
err(e)
|
||||||
|
for _, a := range dirnames {
|
||||||
|
a = c.Path + "/" + a
|
||||||
|
if c.Lifetime != 0 {
|
||||||
|
now := time.Now().UnixMilli()
|
||||||
|
|
||||||
|
f, _ := os.Stat(a)
|
||||||
|
stat := f.Sys().(*syscall.Stat_t)
|
||||||
|
time := time.Unix(stat.Ctim.Unix()).UnixMilli()
|
||||||
|
|
||||||
|
if time+c.Lifetime <= now {
|
||||||
|
os.RemoveAll(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.MaxSize != 0 && stat.Size() > c.MaxSize {
|
||||||
|
os.RemoveAll(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.Close()
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,13 +15,27 @@ import (
|
|||||||
var wr = io.WriteString
|
var wr = io.WriteString
|
||||||
|
|
||||||
type skunkyart struct {
|
type skunkyart struct {
|
||||||
Writer http.ResponseWriter
|
Writer http.ResponseWriter
|
||||||
Args url.Values
|
Args url.Values
|
||||||
Type rune
|
BasePath string
|
||||||
Query string
|
Type rune
|
||||||
Page int
|
Query, QueryRaw string
|
||||||
atom bool
|
Page int
|
||||||
Templates struct {
|
Atom bool
|
||||||
|
Templates struct {
|
||||||
|
About struct {
|
||||||
|
Proxy bool
|
||||||
|
Nsfw bool
|
||||||
|
}
|
||||||
|
|
||||||
|
SomeList string
|
||||||
|
Deviation struct {
|
||||||
|
Post devianter.Post
|
||||||
|
StringTime string
|
||||||
|
Tags string
|
||||||
|
Comments string
|
||||||
|
}
|
||||||
|
|
||||||
GroupUser struct {
|
GroupUser struct {
|
||||||
GR devianter.GRuser
|
GR devianter.GRuser
|
||||||
Admins string
|
Admins string
|
||||||
@ -51,6 +65,19 @@ type skunkyart struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// var Templates struct {
|
||||||
|
// Index string
|
||||||
|
// About string
|
||||||
|
//
|
||||||
|
// GRuser string
|
||||||
|
// Deviation string
|
||||||
|
// List string
|
||||||
|
// Search string
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //go:embed ../html/*
|
||||||
|
// var Templates embed.FS
|
||||||
|
|
||||||
func (s skunkyart) GRUser() {
|
func (s skunkyart) GRUser() {
|
||||||
if len(s.Query) < 1 {
|
if len(s.Query) < 1 {
|
||||||
s.ReturnHTTPError(400)
|
s.ReturnHTTPError(400)
|
||||||
@ -65,7 +92,7 @@ func (s skunkyart) GRUser() {
|
|||||||
switch s.Type {
|
switch s.Type {
|
||||||
case 'a':
|
case 'a':
|
||||||
g := group.GR
|
g := group.GR
|
||||||
s.atom = false
|
s.Atom = false
|
||||||
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":
|
||||||
@ -110,17 +137,15 @@ func (s skunkyart) GRUser() {
|
|||||||
|
|
||||||
case "cover_deviation":
|
case "cover_deviation":
|
||||||
group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation
|
group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation
|
||||||
group.About.BG = devianter.UrlFromMedia(group.About.BGMeta.Media)
|
group.About.BGMeta.Url = s.ConvertDeviantArtUrlToSkunkyArt(group.About.BGMeta.Url)
|
||||||
|
group.About.BG = s.ParseMedia(group.About.BGMeta.Media)
|
||||||
case "group_admins":
|
case "group_admins":
|
||||||
var htm strings.Builder
|
var htm strings.Builder
|
||||||
for _, z := range x.ModuleData.GroupAdmins.Results {
|
for _, z := range x.ModuleData.GroupAdmins.Results {
|
||||||
htm.WriteString(`<p><img src="`)
|
htm.WriteString(`<p><img src="`)
|
||||||
htm.WriteString("/media/")
|
htm.WriteString(UrlBuilder("media", "emojitar", z.User.Username, "?type=a"))
|
||||||
htm.WriteString(z.User.Username)
|
|
||||||
htm.WriteString("?type=a")
|
|
||||||
htm.WriteString(`"><a href="`)
|
htm.WriteString(`"><a href="`)
|
||||||
htm.WriteString("/group_user?type=about&q=")
|
htm.WriteString(UrlBuilder("group_user", "?type=about&q=", z.User.Username))
|
||||||
htm.WriteString(z.User.Username)
|
|
||||||
htm.WriteString(`">`)
|
htm.WriteString(`">`)
|
||||||
htm.WriteString(z.User.Username)
|
htm.WriteString(z.User.Username)
|
||||||
htm.WriteString(`</a></p>`)
|
htm.WriteString(`</a></p>`)
|
||||||
@ -175,24 +200,18 @@ func (s skunkyart) GRUser() {
|
|||||||
s.ReturnHTTPError(400)
|
s.ReturnHTTPError(400)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.atom {
|
if !s.Atom {
|
||||||
s.ExecuteTemplate("html/gruser.htm", &s)
|
s.ExecuteTemplate("html/gruser.htm", &s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// посты
|
// посты
|
||||||
func (s skunkyart) Deviation(author, postname string) {
|
func (s skunkyart) Deviation(author, postname string) {
|
||||||
// поиск ID
|
id_search := regexp.MustCompile("[0-9]+").FindAllString(postname, -1)
|
||||||
re := regexp.MustCompile("[0-9]+").FindAllString(postname, -1)
|
if len(id_search) >= 1 {
|
||||||
if len(re) >= 1 {
|
post := &s.Templates.Deviation
|
||||||
var post struct {
|
|
||||||
Post devianter.Post
|
|
||||||
StringTime string
|
|
||||||
Tags string
|
|
||||||
Comments string
|
|
||||||
}
|
|
||||||
|
|
||||||
id := re[len(re)-1]
|
id := id_search[len(id_search)-1]
|
||||||
post.Post = devianter.DeviationFunc(id, author)
|
post.Post = devianter.DeviationFunc(id, author)
|
||||||
|
|
||||||
post.Post.Description = ParseDescription(post.Post.Deviation.TextContent)
|
post.Post.Description = ParseDescription(post.Post.Deviation.TextContent)
|
||||||
@ -202,9 +221,9 @@ func (s skunkyart) Deviation(author, postname string) {
|
|||||||
// хештэги
|
// хештэги
|
||||||
for _, x := range post.Post.Deviation.Extended.Tags {
|
for _, x := range post.Post.Deviation.Extended.Tags {
|
||||||
var tag strings.Builder
|
var tag strings.Builder
|
||||||
tag.WriteString(` <a href="/search?q=`)
|
tag.WriteString(` <a href="`)
|
||||||
tag.WriteString(x.Name)
|
tag.WriteString(UrlBuilder("search", "?q=", x.Name, "&type=tag"))
|
||||||
tag.WriteString(`&type=tag">#`)
|
tag.WriteString(`">#`)
|
||||||
tag.WriteString(x.Name)
|
tag.WriteString(x.Name)
|
||||||
tag.WriteString("</a>")
|
tag.WriteString("</a>")
|
||||||
|
|
||||||
@ -213,7 +232,7 @@ func (s skunkyart) Deviation(author, postname string) {
|
|||||||
|
|
||||||
post.Comments = s.ParseComments(devianter.CommentsFunc(id, post.Post.Comments.Cursor, s.Page, 1))
|
post.Comments = s.ParseComments(devianter.CommentsFunc(id, post.Post.Comments.Cursor, s.Page, 1))
|
||||||
|
|
||||||
s.ExecuteTemplate("html/deviantion.htm", &post)
|
s.ExecuteTemplate("html/deviantion.htm", &s)
|
||||||
} else {
|
} else {
|
||||||
s.ReturnHTTPError(400)
|
s.ReturnHTTPError(400)
|
||||||
}
|
}
|
||||||
@ -221,17 +240,17 @@ func (s skunkyart) Deviation(author, postname string) {
|
|||||||
|
|
||||||
func (s skunkyart) DD() {
|
func (s skunkyart) DD() {
|
||||||
dd := devianter.DailyDeviationsFunc(s.Page)
|
dd := devianter.DailyDeviationsFunc(s.Page)
|
||||||
ddparsed := s.DeviationList(dd.Deviations, dlist{
|
s.Templates.SomeList = s.DeviationList(dd.Deviations, dlist{
|
||||||
Pages: 0,
|
Pages: 0,
|
||||||
More: dd.HasMore,
|
More: dd.HasMore,
|
||||||
})
|
})
|
||||||
if !s.atom {
|
if !s.Atom {
|
||||||
s.ExecuteTemplate("html/list.htm", &ddparsed)
|
s.ExecuteTemplate("html/list.htm", &s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s skunkyart) Search() {
|
func (s skunkyart) Search() {
|
||||||
s.atom = false
|
s.Atom = false
|
||||||
var e error
|
var e error
|
||||||
ss := &s.Templates.Search
|
ss := &s.Templates.Search
|
||||||
switch s.Type {
|
switch s.Type {
|
||||||
@ -263,3 +282,9 @@ func (s skunkyart) Emojitar(name string) {
|
|||||||
s.ReturnHTTPError(400)
|
s.ReturnHTTPError(400)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s skunkyart) About() {
|
||||||
|
s.Templates.About.Nsfw = CFG.Nsfw
|
||||||
|
s.Templates.About.Proxy = CFG.Proxy
|
||||||
|
s.ExecuteTemplate("html/about.htm", &s)
|
||||||
|
}
|
||||||
|
43
atom.xml
43
atom.xml
@ -1,43 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015" xmlns:media="http://search.yahoo.com/mrss/" xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
|
|
||||||
<link rel="self" href="https://inv.clovius.club/feed/channel/UCuxpxCCevIlF-k-K5YU8XPA"/>
|
|
||||||
<id>yt:channel:UCuxpxCCevIlF-k-K5YU8XPA</id>
|
|
||||||
<yt:channelId>UCuxpxCCevIlF-k-K5YU8XPA</yt:channelId>
|
|
||||||
<icon>https://yt3.googleusercontent.com/ytc/AIdro_n7bKr9iusclFjvYw3U8UR74iTCoMcdGTKI3h55SOG8mSsY=s900-c-k-c0x00ffffff-no-rj</icon>
|
|
||||||
<title>Test</title>
|
|
||||||
<link rel="alternate" href="https://skunky.ebloid.ru"/>
|
|
||||||
<author>
|
|
||||||
<name>lost+skunk</name>
|
|
||||||
<uri>https://skunky.ebloid.ru</uri>
|
|
||||||
</author>
|
|
||||||
<image>
|
|
||||||
<url>https://ebloid.ru/_matrix/media/v3/download/ebloid.ru/enfAtfdjzCQMRNBgLXmiURfJ?allow_redirect=true</url>
|
|
||||||
<title>lost+skunk</title>
|
|
||||||
<link rel="self" href="https://skunky.ebloid.ru"/>
|
|
||||||
</image>
|
|
||||||
<entry>
|
|
||||||
<title>Test</title>
|
|
||||||
<link rel="alternate" href="https://2ip.ua"/>
|
|
||||||
<author>
|
|
||||||
<name>lost+skunk</name>
|
|
||||||
<uri>https://skunky.ebloid.ru</uri>
|
|
||||||
</author>
|
|
||||||
<content type="xhtml">
|
|
||||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<a href="https://2ip.ua">
|
|
||||||
<img src="https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/526e735c-e3da-4542-a339-72ccdf827a00/dh3mfuq-5bd6472c-68f4-428d-bb90-8d461fc21410.jpg/v1/fill/w_1920,h_1080/image.gif?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9MTA4MCIsInBhdGgiOiJcL2ZcLzUyNmU3MzVjLWUzZGEtNDU0Mi1hMzM5LTcyY2NkZjgyN2EwMFwvZGgzbWZ1cS01YmQ2NDcyYy02OGY0LTQyOGQtYmI5MC04ZDQ2MWZjMjE0MTAuanBnIiwid2lkdGgiOiI8PTE5MjAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.S_1DGdd29F5l6Y46Q_bumtGlEEUf_WawZsmF8kBygBs"/>
|
|
||||||
</a>
|
|
||||||
<p>test</p>
|
|
||||||
</div>
|
|
||||||
</content>
|
|
||||||
<published>2024-07-04T00:37:55+00:00</published>
|
|
||||||
<media:group>
|
|
||||||
<media:title>GM Just Announced Their Shutting Down Production in America and Firing Their Workers</media:title>
|
|
||||||
<media:thumbnail url="https://ebloid.ru/_matrix/media/v3/download/ebloid.ru/enfAtfdjzCQMRNBgLXmiURfJ?allow_redirect=true" width="320" height="180"/>
|
|
||||||
<media:description>test</media:description>
|
|
||||||
</media:group>
|
|
||||||
<media:community>
|
|
||||||
<media:statistics views="91247"/>
|
|
||||||
</media:community>
|
|
||||||
</entry>
|
|
||||||
</feed>
|
|
@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"listen": "0.0.0.0:3003",
|
"listen": "0.0.0.0:3003",
|
||||||
"base_uri": null,
|
"base-path": "/skunky/",
|
||||||
"cache": {
|
"cache": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"path": "cache",
|
"path": "cache",
|
||||||
"lifetime": null,
|
"lifetime": null,
|
||||||
"max_size": 10000
|
"max-size": 100000
|
||||||
},
|
},
|
||||||
"proxy": false,
|
"proxy": true,
|
||||||
|
"wixmp-proxy": "http://127.0.0.1:8080",
|
||||||
"nsfw": false
|
"nsfw": false
|
||||||
}
|
}
|
@ -28,9 +28,12 @@ form input, button, select {
|
|||||||
border: 0px;
|
border: 0px;
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
}
|
}
|
||||||
.nsfw, .true {
|
.nsfw, .about-false {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
.about-true {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
.author {
|
.author {
|
||||||
color: seagreen;
|
color: seagreen;
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SkunkyArt</title>
|
<title>SkunkyArt</title>
|
||||||
<link rel="stylesheet" href="gui/css/skunky.css">
|
<link rel="stylesheet" href="{{.BasePath}}gui/css/skunky.css">
|
||||||
</head>
|
</head>
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="/">HOME</a> | <a href="/dd">DD</a></h1>
|
<h1><a href="{{.BasePath}}">HOME</a> | <a href="{{.BasePath}}dd">DD</a></h1>
|
||||||
<form method="get" action="/search">
|
<form method="get" action="{{.BasePath}}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">
|
||||||
<option value="all">All</option>
|
<option value="all">All</option>
|
||||||
@ -19,5 +19,11 @@
|
|||||||
<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>
|
||||||
|
<h2>Instance settings:</h2>
|
||||||
|
<ul>
|
||||||
|
<li><b>NSFW</b>: <span class="about-{{.Templates.About.Nsfw}}">{{if .Templates.About.Nsfw}}YES{{else}}NO{{end}}</span></li>
|
||||||
|
<li><b>Proxyfing</b>: <span class="about-{{.Templates.About.Proxy}}">{{if .Templates.About.Proxy}}YES{{else}}NO{{end}}</span></li>
|
||||||
|
</ul>
|
||||||
|
<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/v1.3" target="_blank">SkunkyArt v1.3</a></p>
|
||||||
</main>
|
</main>
|
||||||
</html>
|
</html>
|
@ -1,13 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SkunkyArt | {{.Post.Deviation.Author.Username}} - {{.Post.Deviation.Title}}</title>
|
<title>SkunkyArt | {{.Templates.Deviation.Post.Deviation.Author.Username}} - {{.Templates.Deviation.Post.Deviation.Title}}</title>
|
||||||
<link rel="stylesheet" href="/gui/css/skunky.css">
|
<link rel="stylesheet" href="{{.BasePath}}gui/css/skunky.css">
|
||||||
</head>
|
</head>
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="/">HOME</a> | <a href="/dd">DD</a></h1>
|
<h1><a href="{{.BasePath}}">HOME</a> | <a href="{{.BasePath}}dd">DD</a></h1>
|
||||||
<form method="get" action="/search">
|
<form method="get" action="{{.BasePath}}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">
|
||||||
<option value="all">All</option>
|
<option value="all">All</option>
|
||||||
@ -17,29 +17,29 @@
|
|||||||
</form>
|
</form>
|
||||||
</header>
|
</header>
|
||||||
<figure>
|
<figure>
|
||||||
<img src="/media/{{.Post.Deviation.Author.Username}}?type=a" width="30px">
|
<img src="{{.BasePath}}media/emojitar/{{.Templates.Deviation.Post.Deviation.Author.Username}}?type=a" width="30px">
|
||||||
<span><strong><a href="/group_user?type=about&q={{.Post.Deviation.Author.Username}}">{{.Post.Deviation.Author.Username}}</a></strong> — {{if (.Post.Deviation.DD)}}
|
<span><strong><a href="{{.BasePath}}group_user?type=about&q={{.Templates.Deviation.Post.Deviation.Author.Username}}">{{.Templates.Deviation.Post.Deviation.Author.Username}}</a></strong> — {{if (.Templates.Deviation.Post.Deviation.DD)}}
|
||||||
<span class="dd" title="Daily Deviation!"><b>{{.Post.Deviation.Title}}</b></span>
|
<span class="dd" title="Daily Deviation!"><b>{{.Templates.Deviation.Post.Deviation.Title}}</b></span>
|
||||||
{{else}}{{.Post.Deviation.Title}}{{end}}
|
{{else}}{{.Templates.Deviation.Post.Deviation.Title}}{{end}}
|
||||||
{{if (ne .Post.Deviation.License "none")}}<mark title="License">{{.Post.Deviation.License}}</mark>{{end}} {{if (.Post.Deviation.AI)}}[🤖]{{end}}
|
{{if (ne .Templates.Deviation.Post.Deviation.License "none")}}<mark title="License">{{.Templates.Deviation.Post.Deviation.License}}</mark>{{end}} {{if (.Templates.Deviation.Post.Deviation.AI)}}[🤖]{{end}}
|
||||||
{{if (.Post.Deviation.NSFW)}}[<span class="nsfw">NSFW</span>]{{end}}
|
{{if (.Templates.Deviation.Post.Deviation.NSFW)}}[<span class="nsfw">NSFW</span>]{{end}}
|
||||||
</span>
|
</span>
|
||||||
<br>
|
<br>
|
||||||
{{if (ne .Post.IMG "")}}
|
{{if (ne .Templates.Deviation.Post.IMG "")}}
|
||||||
<a href="{{.Post.IMG}}" title="open/download image"><img src="{{.Post.IMG}}" width="50%"></a>
|
<a href="{{.Templates.Deviation.Post.IMG}}" title="open/download image"><img src="{{.Templates.Deviation.Post.IMG}}" width="50%"></a>
|
||||||
<br>
|
<br>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if (ne .Tags "")}}
|
{{if (ne .Templates.Deviation.Tags "")}}
|
||||||
{{.Tags}}<br>
|
{{.Templates.Deviation.Tags}}<br>
|
||||||
{{end}}
|
{{end}}
|
||||||
<span>Published: <strong>{{.StringTime}}</strong>; Views: <strong>{{.Post.Deviation.Stats.Views}}</strong>; Favourites: <strong>{{.Post.Deviation.Stats.Favourites}}</strong>; Downloads: <strong>{{.Post.Deviation.Stats.Downloads}}</strong></span>
|
<span>Published: <strong>{{.Templates.Deviation.StringTime}}</strong>; Views: <strong>{{.Templates.Deviation.Post.Deviation.Stats.Views}}</strong>; Favourites: <strong>{{.Templates.Deviation.Post.Deviation.Stats.Favourites}}</strong>; Downloads: <strong>{{.Templates.Deviation.Post.Deviation.Stats.Downloads}}</strong></span>
|
||||||
{{if (ne .Post.Description "")}}
|
{{if (ne .Templates.Deviation.Post.Description "")}}
|
||||||
<figcaption>
|
<figcaption>
|
||||||
{{.Post.Description}}
|
{{.Templates.Deviation.Post.Description}}
|
||||||
</figcaption>
|
</figcaption>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if (ne .Comments "")}}
|
{{if (ne .Templates.Deviation.Comments "")}}
|
||||||
{{.Comments}}
|
{{.Templates.Deviation.Comments}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</figure>
|
</figure>
|
||||||
</main>
|
</main>
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
gallery of {{.Templates.GroupUser.GR.Owner.Username}}
|
gallery of {{.Templates.GroupUser.GR.Owner.Username}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</title>
|
</title>
|
||||||
<link rel="stylesheet" href="/gui/css/skunky.css">
|
<link rel="stylesheet" href="{{.BasePath}}gui/css/skunky.css">
|
||||||
</head>
|
</head>
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="/">HOME</a> | <a href="/dd">DD</a>
|
<h1><a href="{{.BasePath}}">HOME</a> | <a href="{{.BasePath}}dd">DD</a>
|
||||||
| <a href="?q={{.Templates.GroupUser.GR.Owner.Username}}&type={{if eq .Type 'a'}}gallery">Gallery{{else}}about">About{{end}}</a>
|
| <a href="?q={{.Templates.GroupUser.GR.Owner.Username}}&type={{if eq .Type 'a'}}gallery">Gallery{{else}}about">About{{end}}</a>
|
||||||
| <a href="?q={{.Templates.GroupUser.GR.Owner.Username}}&type=gallery&atom=true">RSS</a></h1>
|
| <a href="?q={{.Templates.GroupUser.GR.Owner.Username}}&type=gallery&atom=true">RSS</a></h1>
|
||||||
<form method="get" action="/search">
|
<form method="get" action="{{.BasePath}}search">
|
||||||
<input type="gallery" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
|
<input type="gallery" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
|
||||||
<input type="hidden" name="usr" value="{{.Templates.GroupUser.GR.Owner.Username}}">
|
<input type="hidden" name="usr" value="{{.Templates.GroupUser.GR.Owner.Username}}">
|
||||||
<select name="type">
|
<select name="type">
|
||||||
@ -32,7 +32,7 @@
|
|||||||
{{.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}}
|
||||||
|
|
||||||
<img src="/media/{{.Templates.GroupUser.GR.Owner.Username}}?type=a" width="30px" height="30px"> <b>{{.Templates.GroupUser.GR.Owner.Username}}</b>
|
<img src="{{.BasePath}}media/emojitar/{{.Templates.GroupUser.GR.Owner.Username}}?type=a" width="30px" height="30px"> <b>{{.Templates.GroupUser.GR.Owner.Username}}</b>
|
||||||
{{if (eq .Templates.GroupUser.About.A.Gender "male")}}
|
{{if (eq .Templates.GroupUser.About.A.Gender "male")}}
|
||||||
♂️
|
♂️
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SkunkyArt</title>
|
<title>SkunkyArt</title>
|
||||||
<link rel="stylesheet" href="gui/css/skunky.css"
|
<link rel="stylesheet" href="{{.}}gui/css/skunky.css"/>
|
||||||
</head>
|
</head>
|
||||||
<main>
|
<main>
|
||||||
<center>
|
<center>
|
||||||
<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">
|
||||||
<option value="all">All</option>
|
<option value="all">All</option>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
</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><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>
|
||||||
</center>
|
</center>
|
||||||
</main>
|
</main>
|
||||||
</html>
|
</html>
|
@ -2,12 +2,12 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SkunkyArt</title>
|
<title>SkunkyArt</title>
|
||||||
<link rel="stylesheet" href="gui/css/skunky.css">
|
<link rel="stylesheet" href="{{.BasePath}}gui/css/skunky.css">
|
||||||
</head>
|
</head>
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="/">HOME</a> | <a href="/dd">DD</a> | <a href="?atom=true">RSS</a></h1>
|
<h1><a href="{{.BasePath}}">HOME</a> | <a href="{{.BasePath}}dd">DD</a> | <a href="?atom=true">RSS</a></h1>
|
||||||
<form method="get" action="/search">
|
<form method="get" action="{{.BasePath}}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">
|
||||||
<option value="all">All</option>
|
<option value="all">All</option>
|
||||||
@ -16,6 +16,6 @@
|
|||||||
<button type="submit">Search!</button>
|
<button type="submit">Search!</button>
|
||||||
</form>
|
</form>
|
||||||
</header>
|
</header>
|
||||||
{{.}}
|
{{.Templates.SomeList}}
|
||||||
</main>
|
</main>
|
||||||
</html>
|
</html>
|
@ -1,12 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SkunkyArt | Search "{{.Query}}"</title>
|
<title>SkunkyArt | Search "{{.QueryRaw}}"</title>
|
||||||
<link rel="stylesheet" href="/gui/css/skunky.css">
|
<link rel="stylesheet" href="{{.BasePath}}gui/css/skunky.css">
|
||||||
</head>
|
</head>
|
||||||
<main>
|
<main>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href="/">HOME</a> | <a href="/dd">DD</a></h1>
|
<h1><a href="{{.BasePath}}">HOME</a> | <a href="{{.BasePath}}dd">DD</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">
|
||||||
|
Loading…
Reference in New Issue
Block a user