Path realization (dirty)

This commit is contained in:
lost+skunk 2024-04-08 01:52:07 +03:00
parent 582f870578
commit ab662f414c
28 changed files with 305 additions and 379 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
**/cache

View File

@ -34,5 +34,4 @@ $HTTP["host"] == "sa.example.com" {
))
)
}
```
Учтите тот факт, что в настоящее время SkunkyArt корректно работать может только на поддомене.
```

View File

@ -1,5 +1,6 @@
{
"listen": "0.0.0.0:3003",
"base_uri": null,
"cache": {
"enabled": true,
"path": "cache",

View File

@ -39,6 +39,10 @@ func main() {
page, _ := strconv.ParseInt(r.URL.Query().Get("p"), 10, 32)
q := url.QueryEscape(r.URL.Query().Get("q"))
if util.Conf.Base_uri != "" {
w.Header().Set("Content-Location", util.Conf.Base_uri)
}
switch e {
case "image":
fmt.Fprintln(w, misc.Getimage(p, url.QueryEscape(r.URL.Query().Get("t"))))
@ -97,6 +101,10 @@ func main() {
}
func endpoint(url string) (string, string) {
if util.Conf.Base_uri != "" {
url = strings.Replace(url, util.Conf.Base_uri, "/", 1)
}
end := strings.Index(url[1:], "/")
if end == -1 {
return url[1:], ""

View File

@ -1,21 +1,20 @@
package misc
import (
"bytes"
"encoding/json"
t "html/template"
"skunkyart/util"
"strconv"
)
func DD(page int, out chan string) {
var buf bytes.Buffer
{
var (
j struct {
Deviations []util.Deviation
}
d, p string
tmp struct {
D, P string
}
)
if page == 0 {
@ -26,17 +25,14 @@ func DD(page int, out chan string) {
json.Unmarshal([]byte(rawjson), &j)
for _, a := range j.Deviations {
d += util.Images(a, a.Media, false)
tmp.D += util.Images(a, a.Media, false)
}
if page > 1 {
p += "<a href=\"/dd?p=" + strconv.Itoa(int(page)-1) + "\"><-- Back</a> "
tmp.P += "<a href=\"" + util.Conf.Base_uri + "dd?p=" + strconv.Itoa(int(page)-1) + "\"><-- Back</a> "
}
p += "<a href=\"/dd?p=" + strconv.Itoa(int(page)+1) + "\">Next --></a>"
tmp.P += "<a href=\"" + util.Conf.Base_uri + "dd?p=" + strconv.Itoa(int(page)+1) + "\">Next --></a>"
tmp, _ := t.ParseFiles("templates/dd.htm")
tmp.Execute(&buf, t.HTML(d))
tmp.ExecuteTemplate(&buf, "P", t.HTML(p))
out <- util.TmpExec("templates/dd.htm", &tmp)
}
out <- buf.String()
}

View File

@ -1,17 +1,18 @@
package misc
import (
"bytes"
"encoding/json"
"html/template"
"math"
"os"
"skunkyart/util"
"strconv"
)
func Search(q, p, scope string, output chan string) {
var buf bytes.Buffer
var tmp struct {
Results, Pages string
Total int
}
if q != "" {
var j struct {
EstTotal int
@ -30,10 +31,6 @@ func Search(q, p, scope string, output chan string) {
json.Unmarshal([]byte(rawjson), &j)
var tmp struct {
Results, Pages string
Total int
}
for _, a := range j.Deviations {
tmp.Results += util.Images(a, a.Media, false)
}
@ -45,7 +42,7 @@ func Search(q, p, scope string, output chan string) {
if x == 417 {
break
}
tmp.Pages += "<a href=\"/search?p=" + strconv.Itoa(x+1) + "&scope=all&q=" + q + "\">" + strconv.Itoa(x+1) + "</a> "
tmp.Pages += "<a href=\"" + util.Conf.Base_uri + "search?p=" + strconv.Itoa(x+1) + "&scope=all&q=" + q + "\">" + strconv.Itoa(x+1) + "</a> "
}
case "tag":
if p == "" {
@ -53,20 +50,14 @@ func Search(q, p, scope string, output chan string) {
}
next, _ := strconv.ParseInt(p, 10, 32)
if int(next) > 1 {
tmp.Pages += "<a href=\"/search?p=" + strconv.Itoa(int(next)-1) + "&scope=tag&q=" + q + "\"><-- Back</a> "
tmp.Pages += "<a href=\"" + util.Conf.Base_uri + "search?p=" + strconv.Itoa(int(next)-1) + "&scope=tag&q=" + q + "\"><-- Back</a> "
}
tmp.Pages += "<a href=\"/search?p=" + strconv.Itoa(int(next)+1) + "&scope=tag&q=" + q + "\">Next --></a>"
tmp.Pages += "<a href=\"" + util.Conf.Base_uri + "search?p=" + strconv.Itoa(int(next)+1) + "&scope=tag&q=" + q + "\">Next --></a>"
default:
output <- "Missing or invalid scope."
}
tmpl, _ := template.ParseFiles("templates/search/search.htm")
tmpl.Execute(&buf, tmp.Total)
tmpl.ExecuteTemplate(&buf, "R", template.HTML(tmp.Results))
tmpl.ExecuteTemplate(&buf, "P", template.HTML(tmp.Pages))
} else {
doc, _ := os.ReadFile("templates/search/search-base.htm")
output <- string(doc)
output <- "Missing query."
}
output <- buf.String()
output <- util.TmpExec("templates/search/search.htm", &tmp)
}

View File

@ -62,9 +62,7 @@ func GetComments(uri, cursor string, page, typ int, id []string) *string {
rawjson, next, prev := js(cursor, page, id, typ)
err := json.Unmarshal([]byte(*rawjson), &comments)
if err != nil {
fmt.Println(err)
}
util.Err(err)
// обработка жирсона
var htm string
@ -85,9 +83,7 @@ func GetComments(uri, cursor string, page, typ int, id []string) *string {
}
err := json.Unmarshal([]byte(b.TextContent.Html.Markup), &comments)
if err != nil {
fmt.Println(err)
}
util.Err(err)
for _, a := range comments.Blocks {
msgbody = a.Text
@ -120,7 +116,7 @@ func GetComments(uri, cursor string, page, typ int, id []string) *string {
msgbody = util.Parse(msgbody)
htm += fmt.Sprintf("<div class=\"msg\" style=\"%[10]s\"><p id=\"%[2]d\"><img src=\"/avatar/%[1]s\" width=\"30px\" height=\"30px\"/> <a href=\"/user/%[1]s\"><b class=\"%[6]s %[5]t\">%[1]s</b></a> %[4]s %[9]s<p>%[3]s<p>👍: %[7]d ⏩: %[8]d</p></div>\n", b.User.Username, b.CommentId, msgbody, b.Posted.UTC().String(), b.User.IsBanned, isauthor, b.Likes, b.Replies, reply, space)
htm += fmt.Sprintf("<div class=\"msg\" style=\"%[10]s\"><p id=\"%[2]d\"><img src=\""+util.Conf.Base_uri+"avatar/%[1]s\" width=\"30px\" height=\"30px\"/> <a href=\""+util.Conf.Base_uri+"user/%[1]s\"><b class=\"%[6]s %[5]t\">%[1]s</b></a> %[4]s %[9]s<p>%[3]s<p>👍: %[7]d ⏩: %[8]d</p></div>\n", b.User.Username, b.CommentId, msgbody, b.Posted.UTC().String(), b.User.IsBanned, isauthor, b.Likes, b.Replies, reply, space)
}
// если комментариев больше, чем 0, то отображаем их, иначе пишем, что комментов нет.

View File

@ -1,9 +1,7 @@
package post
import (
"bytes"
"encoding/json"
"html/template"
"regexp"
"skunkyart/util"
"strconv"
@ -94,7 +92,7 @@ func _post(id []string, author string, url string, page int) string {
tmp.Tags = ""
for _, a := range j.Deviation.Extended.Tags {
tmp.Tags += "<a href=\"/search?q=" + a.Name + "&scope=tag\">#" + a.Name + "</a> "
tmp.Tags += "<a href=\"" + util.Conf.Base_uri + "search?q=" + a.Name + "&scope=tag\">#" + a.Name + "</a> "
}
tmp.Comments = ""
@ -116,7 +114,6 @@ func Get(uri string, page int, output chan string) {
id := regexp.MustCompile("[0-9]+").FindAllString(uri, -1)
var buffer bytes.Buffer
body, status, _, _ := util.Request(url, "")
if status == 200 {
body = body[strings.Index(body, " by ")+4:]
@ -127,14 +124,7 @@ func Get(uri string, page int, output chan string) {
}
// темплейт
templ, _ := template.ParseFiles("templates/post.htm")
templ.Execute(&buffer, tmp)
templ.ExecuteTemplate(&buffer, "T", template.HTML(tmp.Tags))
templ.ExecuteTemplate(&buffer, "D", template.HTML(tmp.Description))
templ.ExecuteTemplate(&buffer, "R", template.HTML(tmp.Recomendations))
templ.ExecuteTemplate(&buffer, "C", template.HTML(string(tmp.Comments)))
output <- buffer.String()
output <- util.TmpExec("templates/post.htm", &tmp)
} else {
output <- "Something went wrong. Status: " + strconv.Itoa(int(status))
}

View File

@ -38,6 +38,8 @@ form input, button, select {
color: rgb(160, 0, 147);
}
.content {
background-color: #001624;
border-radius: 3px;
display: flex;
flex-wrap: wrap;
justify-content: center;

View File

@ -3,10 +3,10 @@
<head>
<meta charset="UTF-8">
<title>Daily Deviations | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
<link rel="stylesheet" href="static/base.css">
</head>
<body>
<form method="get" action="/search">
<form method="get" action="search">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<select name="scope">
<option value="all">All</option>
@ -16,11 +16,9 @@
</form>
<h1>Daily Deviations</h1>
<div class="content">
{{.}}
{{.D}}
</div>
{{define "P"}}
<hr>
{{.}}
<hr>
{{.P}}
</body>
</html>
{{end}}
</html>

View File

@ -3,17 +3,19 @@
<head>
<meta charset="UTF-8">
<title>SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
<link rel="stylesheet" href="static/base.css">
</head>
<body>
<form method="get" action="/search">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<select name="scope">
<option value="all">All</option>
<option value="tag">Tag</option>
</select>
<button type="submit">Search!</button>
</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>
<center>
<form method="get" action="search">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<select name="scope">
<option value="all">All</option>
<option value="tag">Tag</option>
</select>
<button type="submit">Search!</button>
</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>
</center>
</body>
</html>

View File

@ -1,12 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
!BAZE!
<meta charset="UTF-8">
<title>{{.Author}} — {{.Postname}} | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
<link rel="stylesheet" href="static/base.css">
</head>
<body>
<form method="get" action="/search">
<form method="get" action="search">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<select name="scope">
<option value="all">All</option>
@ -15,39 +16,35 @@
<button type="submit">Search!</button>
</form>
<figure>
<img src="/avatar/{{.Author}}" width="30px">
<span><strong><a href="/user/{{.Author}}">{{.Author}}</a></strong> — {{if (.DD)}}
<img src="avatar/{{.Author}}" width="30px">
<span><strong><a href="user/{{.Author}}">{{.Author}}</a></strong> — {{if (.DD)}}
<span class="dd" title="Daily Deviation!"><b>{{.Postname}}</b></span>
{{else}}{{.Postname}}{{end}}
{{if (ne .License "none")}}({{.License}}){{end}} {{if (.Ai)}}[🤖]{{end}}
{{if (.Nsfw)}}[<span class="nsfw">NSFW</span>]{{end}}
</span>
<br>
{{if (ne .Img "/image/")}}
{{if (ne .Img "no")}}
<img src="{{.Img}}" width="50%">
<br>
{{end}}
<span>Published: <strong>{{.Time}}</strong>; Views: <strong>{{.Views}}</strong>; Favourites: <strong>{{.FavsCount}}</strong>; Downloads: <strong>{{.Downloads}}</strong></span>
{{define "T"}}
{{if (ne . "")}}
{{if (ne .Tags "")}}
<br>
<span>Tags: <strong>{{.}}</strong></span>
<span>Tags: <strong>{{.Tags}}</strong></span>
{{end}}
{{if (ne .Description "")}}
<br>
<br>
<figcaption>{{.Description}}</figcaption>
{{end}}
{{define "R"}}
{{if (ne .Recomendations "")}}
<h2>See also:</h2>
<div class="content">
{{.}}
{{.Recomendations}}
</div>
{{end}}
<br>
<br>
{{define "D"}}
<figcaption>{{.}}</figcaption>
{{end}}
{{define "C"}}
{{.}}
{{.Comments}}
</figure>
</body>
</html>
{{end}}
</html>

View File

@ -1,18 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta charset="UTF-8">
<title>Search | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
</head>
<body>
<form method="get" action="/search">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<select name="scope">
<option value="all">All</option>
<option value="tag">Tag</option>
</select>
<button type="submit">Search!</button>
</form>
</body>
</html>

View File

@ -1,12 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
!BAZE!
<meta charset="UTF-8">
<title>Search | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
<link rel="stylesheet" href="static/base.css">
</head>
<body>
<form method="get" action="/search">
<form method="get" action="search">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<select name="scope">
<option value="all">All</option>
@ -14,18 +15,16 @@
</select>
<button type="submit">Search!</button>
</form>
<hr>
{{if (ne . 0)}}
<h1>Total resuls: {{.}}</h1>
{{if (ne .Results "")}}
{{if (ne .Total 0)}}
<h1>Total resuls: {{.Total}}</h1>
{{end}}
{{define "R"}}
<div class="content">
{{.}}
{{.Results}}
</div>
{{.Pages}}
{{else}}
<p>No results :(</p>
{{end}}
{{define "P"}}
<hr>
{{.}}
</body>
</html>
{{end}}
</html>

View File

@ -1,20 +1,23 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
!BAZE!
<title>{{.Name}}'s Gallery | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
<link rel="stylesheet" href="static/base.css">
</head>
<body>
<img src="/avatar/{{.Name}}" width="60px"><h1>Gallery of {{.Name}}</h1></img>
<h2><a href="/user/{{.Name}}">Home</a> | <a href="/user/{{.Name}}?a=search">Search</a></h2>
{{define "G"}}
<img src="avatar/{{.Name}}" width="60px"><h1>Gallery of {{.Name}}</h1></img>
<h2><form method="get" action="">
<input type="text" name="q" placeholder="Search {{.Name}}'s Gallery!" autocomplete="off" autocapitalize="none" spellcheck="false">
<input type="hidden" name="a" value="search">
<button type="submit">Search!</button>
</form> <a href="user/{{.Name}}">Home</a>
</h2>
<div class="content">
{{.}}
{{.Posts}}
</div>
{{end}}
{{define "P"}}
<hr>
<p><b>Pages: {{.}}</b></p>
<p><b>Pages: {{.Nav}}</b></p>
</body>
</html>
{{end}}
</html>

View File

@ -1,15 +1,16 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
!BAZE!
<title>{{.Name}} | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
<link rel="stylesheet" href="static/base.css">
</head>
<body>
{{if (ne .Bg "/image/")}}
{{if (ne .Bg "no")}}
<img src="{{.Bg}}" width="30%" title="{{.Bgname}}">
{{end}}
<h1><img src="/avatar/{{.Name}}" width="60px">{{.Name}} {{.Gender}}</h1>
<h2><a href="/user/{{.Name}}?a=gallery">Gallery</a></h2>
<h1><img src="avatar/{{.Name}}" width="60px">{{.Name}} {{.Gender}}</h1>
<h2><a href="user/{{.Name}}?a=gallery">Gallery</a></h2>
<p>Watchers: {{.Watchers}}; Watching: {{.Watching}}; Comments on Profile: {{.CMMRCPF}}; Posts: {{.Posts}}; Pageviews: {{.Pageviews}}; Comments: {{.CM}};
Favourites: {{.Fav}}; Friends: {{.Friends}}
</p>
@ -18,22 +19,12 @@
<a href="https://{{.Site}}" target="_blank">{{.SiteTitle}}</a>
</p>
<p><i title="User status">{{.Status}}</i></p>
{{define "S"}}
<h2>Social Links</h2>
<p>
{{.}}
</p>
{{end}}
{{define "I"}}
<p>{{.Social}}</p>
<h2>Interests</h2>
<p>{{.}}</p>
{{end}}
{{define "D"}}
<p>{{.Interests}}</p>
<h2>About me</h2>
<p>{{.}}</p>
{{end}}
{{define "C"}}
{{.}}
<p>{{.Description}}</p>
{{.Comments}}
</body>
</html>
{{end}}
</html>

View File

@ -1,16 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Search {{.}}'s Gallery | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
</head>
<body>
<img src="/avatar/{{.}}" width="60px"><h1>Search gallery of {{.}}.</h1></img>
<h2><a href="/user/{{.}}">Home</a> | <a href="/user/{{.}}?a=gallery">Gallery</a></h2>
<form method="get" action="/user/{{.}}">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<input type="hidden" name="a" value="search">
<button type="submit">Search!</button>
</form>
</body>
</html>

View File

@ -1,25 +1,26 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
!BAZE!
<title>Search {{.Name}}'s Gallery | SkunkyArt</title>
<link rel="stylesheet" href="/static/base.css">
<link rel="stylesheet" href="static/base.css">
</head>
<body>
<img src="/avatar/{{.Name}}" width="60px"><h1>Search gallery of {{.Name}}. Total Deviations: {{.Total}}</h1></img>
<h2><a href="/user/{{.Name}}">Home</a> | <a href="/user/{{.Name}}?a=gallery">Gallery</a></h2>
<form method="get" action="/user/{{.Name}}">
<input type="text" name="q" placeholder="Search for ..." autocomplete="off" autocapitalize="none" spellcheck="false">
<input type="hidden" name="a" value="search">
<button type="submit">Search!</button>
</form>
{{define "R"}}
<img src="avatar/{{.Name}}" width="60px"><h1>Search gallery of {{.Name}}. Total Deviations: {{.Total}}</h1></img>
<h2><form method="get" action="">
<input type="text" name="q" placeholder="Search {{.Name}}'s Gallery!" autocomplete="off" autocapitalize="none" spellcheck="false">
<input type="hidden" name="a" value="search">
<button type="submit">Search!</button>
</form> <a href="user/{{.Name}}">Home</a>
</h2>
{{if (ne .Total 0)}}
<div class="content">
{{.}}
{{.Results}}
</div>
{{end}}
{{define "P"}}
<hr>
<p><b>Pages: {{.}}</b></p>
<p><b>Pages: {{.Pages}}</b></p>
{{else}}
<p>Gallery is empty :(</p>
{{end}}
</body>
</html>
{{end}}
</html>

View File

@ -1,7 +1,7 @@
Нужно сделать:
- провести оптимизацию кода
- кеширование жсона
- реализовать работу на определённом пути (https://example.com/skunkyart)
- ~~реализовать работу на определённом пути (https://example.com/skunkyart)~~
- ~~добавить устаревание кеша и его максимальный вес~~
- ~~проксирование и кеширование гифок~~
- картинки в комментариях

View File

@ -1,10 +1,7 @@
package user
import (
"bytes"
"encoding/json"
"fmt"
"html/template"
"skunkyart/post"
"skunkyart/util"
"strconv"
@ -12,122 +9,102 @@ import (
)
type Tmp struct {
Watchers, Posts, Watching, Pageviews, CMMRCPF, CM, Fav, Friends int
Name, Description, Bg, Bgname, Country, RegDate, Gender, Site, SiteTitle, Social, Interests, Status string
Watchers, Posts, Watching, Pageviews, CMMRCPF, CM, Fav, Friends int
Name, Description, Bg, Bgname, Country, RegDate, Gender, Site, SiteTitle, Social, Interests, Status, Comments string
}
func about(name *string, page int, output chan string) {
ums := time.Now().Unix()
uid := make([]string, 1)
var buf bytes.Buffer
{
var tmp Tmp
var j ab
// парсинг
rawjson := util.Puppy("dauserprofile/init/about?username=" + *name)
err := json.Unmarshal([]byte(rawjson), &j)
if err != nil {
fmt.Println(err)
if rawjson == "Something went wrong. Status: 403" {
output <- "Rate limit from Cloudfront."
} else {
output <- "Something went wrong."
}
} else {
// ошибки
switch j.ErrorDescription {
case "User deactivated.":
output <- "User deactivated their account or has been banned."
case "user_not_found.":
output <- "Not exists user."
}
j.ErrorDescription = ""
uid[0] = strconv.Itoa(j.Gruser.GruserId)
for _, a := range j.Gruser.Page.Modules {
if a.ModuleData.About.Country != "" {
tmp.Country = a.ModuleData.About.Country
}
switch a.Name {
case "about":
var j struct {
Blocks []struct {
Text string
// InlineStyleRanges []struct {
// Offset, Length int
// Style string
// EntityMap struct {
// }
// }
}
}
json.Unmarshal([]byte(a.ModuleData.About.TextContent.Html.Markup), &j)
for _, a := range j.Blocks {
tmp.Description += a.Text + "<p>"
}
case "cover_deviation":
tmp.Bg = util.Images(a.ModuleData.CoverDeviation.CoverDeviation, a.ModuleData.CoverDeviation.CoverDeviation.Media, true)
tmp.Bgname = a.ModuleData.CoverDeviation.CoverDeviation.Title
}
if a.ModuleData.About.DeviantFor > 0 {
tmp.RegDate = time.Unix(ums-a.ModuleData.About.DeviantFor, 0).UTC().String()
}
switch a.ModuleData.About.Gender {
case "female":
tmp.Gender = "♀️"
case "male":
tmp.Gender = "♂️"
}
if a.ModuleData.About.Website != "" {
tmp.Site = a.ModuleData.About.Website
if a.ModuleData.About.WebsiteLabel != "" {
tmp.SiteTitle = a.ModuleData.About.WebsiteLabel
} else {
tmp.SiteTitle = a.ModuleData.About.Website
}
}
for _, a := range a.ModuleData.About.SocialLinks {
tmp.Social += "<a href=\"" + a.Value + "\" target=\"_blank\">" + a.Value + "</a><p>"
}
for _, a := range a.ModuleData.About.Interests {
tmp.Interests += "<b>" + a.Label + "</b>: " + a.Value + "<p>"
}
if a.ModuleData.About.Tagline != "" {
tmp.Status = a.ModuleData.About.Tagline
}
// говно
tmp.Watchers = j.PageExtraData.Stats.Watchers
tmp.Posts = j.PageExtraData.Stats.Deviations
tmp.Watching = j.PageExtraData.Stats.Watching
tmp.CMMRCPF = j.PageExtraData.Stats.CommentsReceivedProfile
tmp.CM = j.PageExtraData.Stats.CommentsMade
tmp.Fav = j.PageExtraData.Stats.Favourites
tmp.Friends = j.PageExtraData.Stats.Friends
tmp.Name = j.Owner.Username
}
// темплейты
tmpl, _ := template.ParseFiles("templates/user/info.htm")
tmpl.Execute(&buf, tmp)
tmpl.ExecuteTemplate(&buf, "S", template.HTML(tmp.Social))
tmpl.ExecuteTemplate(&buf, "I", template.HTML(tmp.Interests))
tmpl.ExecuteTemplate(&buf, "D", template.HTML(tmp.Description))
tmpl.ExecuteTemplate(&buf, "C", template.HTML(*post.GetComments("user/"+tmp.Name, "", page+1, 4, uid)))
e := rerror(&rawjson)
if e != "" {
output <- e
}
}
json.Unmarshal([]byte(rawjson), &j)
output <- buf.String()
// ошибки
uid[0] = strconv.Itoa(j.Gruser.GruserId)
for _, a := range j.Gruser.Page.Modules {
if a.ModuleData.About.Country != "" {
tmp.Country = a.ModuleData.About.Country
}
switch a.Name {
case "about":
var j struct {
Blocks []struct {
Text string
// InlineStyleRanges []struct {
// Offset, Length int
// Style string
// EntityMap struct {
// }
// }
}
}
json.Unmarshal([]byte(a.ModuleData.About.TextContent.Html.Markup), &j)
for _, a := range j.Blocks {
tmp.Description += a.Text + "<p>"
}
case "cover_deviation":
tmp.Bg = util.Images(a.ModuleData.CoverDeviation.CoverDeviation, a.ModuleData.CoverDeviation.CoverDeviation.Media, true)
tmp.Bgname = a.ModuleData.CoverDeviation.CoverDeviation.Title
}
if a.ModuleData.About.DeviantFor > 0 {
tmp.RegDate = time.Unix(ums-a.ModuleData.About.DeviantFor, 0).UTC().String()
}
switch a.ModuleData.About.Gender {
case "female":
tmp.Gender = "♀️"
case "male":
tmp.Gender = "♂️"
}
if a.ModuleData.About.Website != "" {
tmp.Site = a.ModuleData.About.Website
if a.ModuleData.About.WebsiteLabel != "" {
tmp.SiteTitle = a.ModuleData.About.WebsiteLabel
} else {
tmp.SiteTitle = a.ModuleData.About.Website
}
}
for _, a := range a.ModuleData.About.SocialLinks {
tmp.Social += "<a href=\"" + a.Value + "\" target=\"_blank\">" + a.Value + "</a><p>"
}
for _, a := range a.ModuleData.About.Interests {
tmp.Interests += "<b>" + a.Label + "</b>: " + a.Value + "<p>"
}
if a.ModuleData.About.Tagline != "" {
tmp.Status = a.ModuleData.About.Tagline
}
// говно
tmp.Watchers = j.PageExtraData.Stats.Watchers
tmp.Posts = j.PageExtraData.Stats.Deviations
tmp.Watching = j.PageExtraData.Stats.Watching
tmp.CMMRCPF = j.PageExtraData.Stats.CommentsReceivedProfile
tmp.CM = j.PageExtraData.Stats.CommentsMade
tmp.Fav = j.PageExtraData.Stats.Favourites
tmp.Friends = j.PageExtraData.Stats.Friends
tmp.Name = j.Owner.Username
tmp.Comments = *post.GetComments("user/"+tmp.Name, "", page+1, 4, uid)
}
output <- util.TmpExec("templates/user/info.htm", tmp)
}
}

View File

@ -1,16 +1,12 @@
package user
import (
"bytes"
"encoding/json"
"fmt"
"html/template"
"skunkyart/util"
"strconv"
)
func gallery(name *string, output chan string, page string) {
var buf bytes.Buffer
{
var tmp struct {
Posts, Name, Nav string
@ -35,38 +31,30 @@ func gallery(name *string, output chan string, page string) {
rawjson := util.Puppy("dauserprofile/init/gallery?username=" + *name + "&page=" + page + "&deviations_limit=50&with_subfolders=false")
err := json.Unmarshal([]byte(rawjson), &j)
if err != nil {
fmt.Println(err)
if rawjson == "Something went wrong. Status: 403" {
output <- "Rate limit from CloudFront."
} else {
output <- "Something went wrong."
}
} else {
for _, a := range j.Gruser.Page.Modules {
if a.ModuleData.FolderDeviations.Username != "" {
tmp.Name = a.ModuleData.FolderDeviations.Username
}
if a.ModuleData.FolderDeviations.TotalPageCount != 0 {
tmp.TP = a.ModuleData.FolderDeviations.TotalPageCount
}
for _, a := range a.ModuleData.FolderDeviations.Deviations {
tmp.Posts += util.Images(a, a.Media, false)
}
tmp.Nav = ""
for x := 0; x < tmp.TP; x++ {
tmp.Nav += "<a href=\"/user/" + tmp.Name + "?a=gallery&p=" + strconv.Itoa(x+1) + "\">" + strconv.Itoa(x+1) + "</a> "
}
}
util.Err(err)
e := rerror(&rawjson)
if e != "" {
output <- e
}
tmpl, _ := template.ParseFiles("templates/user/gallery.htm")
tmpl.Execute(&buf, tmp)
tmpl.ExecuteTemplate(&buf, "G", template.HTML(tmp.Posts))
tmpl.ExecuteTemplate(&buf, "P", template.HTML(tmp.Nav))
}
for _, a := range j.Gruser.Page.Modules {
if a.ModuleData.FolderDeviations.Username != "" {
tmp.Name = a.ModuleData.FolderDeviations.Username
}
if a.ModuleData.FolderDeviations.TotalPageCount != 0 {
tmp.TP = a.ModuleData.FolderDeviations.TotalPageCount
}
output <- buf.String()
for _, a := range a.ModuleData.FolderDeviations.Deviations {
tmp.Posts += util.Images(a, a.Media, false)
}
tmp.Nav = ""
for x := 0; x < tmp.TP; x++ {
tmp.Nav += "<a href=\"" + util.Conf.Base_uri + "user/" + tmp.Name + "?a=gallery&p=" + strconv.Itoa(x+1) + "\">" + strconv.Itoa(x+1) + "</a> "
}
}
output <- util.TmpExec("templates/user/gallery.htm", &tmp)
}
}

View File

@ -1,6 +1,7 @@
package user
import (
"encoding/json"
"skunkyart/util"
)
@ -45,3 +46,27 @@ type ab struct {
}
}
}
func rerror(err *string) string {
if len(*err) < 100 {
var j struct {
ErrorDescription string
}
json.Unmarshal([]byte(*err), &j)
switch j.ErrorDescription {
case "User deactivated.":
return "User deactivated their account or has been banned."
case "user_not_found.":
return "Not exists user."
default:
if *err == "Something went wrong. Status: 403" {
return "Rate limit from CloudFront."
} else {
return "Something went wrong."
}
}
}
return ""
}

View File

@ -1,17 +1,13 @@
package user
import (
"bytes"
"encoding/json"
"fmt"
"html/template"
"math"
"skunkyart/util"
"strconv"
)
func search(user, query *string, page int, output chan string) {
var buf bytes.Buffer
{
var tmp struct {
Total int
@ -26,31 +22,25 @@ func search(user, query *string, page int, output chan string) {
if *query != "" {
rawjson := util.Puppy("dashared/gallection/search?username=" + *user + "&q=" + *query + "&offset=" + strconv.Itoa(50*page) + "&type=gallery&order=most-recent&init=true&limit=50")
err := json.Unmarshal([]byte(rawjson), &q)
if err != nil {
fmt.Println(err)
} else {
if q.EstTotal != 0 {
tmp.Total = q.EstTotal
}
util.Err(err)
for _, a := range q.Results {
tmp.Results += util.Images(a, a.Media, false)
}
tmp.Pages = ""
tmp.Name = *user
for x := 0; x < int(math.Round(float64(q.EstTotal/50))); x++ {
tmp.Pages += "<a href=\"/user/" + tmp.Name + "?a=search&p=" + strconv.Itoa(x+1) + "&q=" + *query + "\">" + strconv.Itoa(x+1) + "</a> "
}
if q.EstTotal != 0 {
tmp.Total = q.EstTotal
}
tmpl, _ := template.ParseFiles("templates/user/search.htm")
tmpl.Execute(&buf, tmp)
tmpl.ExecuteTemplate(&buf, "R", template.HTML(tmp.Results))
tmpl.ExecuteTemplate(&buf, "P", template.HTML(tmp.Pages))
for _, a := range q.Results {
tmp.Results += util.Images(a, a.Media, false)
}
tmp.Pages = ""
tmp.Name = *user
for x := 0; x < int(math.Round(float64(q.EstTotal/50))); x++ {
tmp.Pages += "<a href=\"/user/" + tmp.Name + "?a=search&p=" + strconv.Itoa(x+1) + "&q=" + *query + "\">" + strconv.Itoa(x+1) + "</a> "
}
output <- util.TmpExec("templates/user/search.htm", &tmp)
} else {
tmpl, _ := template.ParseFiles("templates/user/search-base.htm")
tmpl.Execute(&buf, *user)
output <- "Missing query."
}
}
output <- buf.String()
}

View File

@ -16,9 +16,7 @@ func check(what ...string) {
dir, err := os.Open(Conf.Cache.Path)
if err != nil {
err = os.Mkdir(Conf.Cache.Path, 0700)
if err != nil {
panic(fmt.Sprintln(err))
}
Err(err)
}
stat, _ := dir.Stat()
@ -71,9 +69,7 @@ func Cache(img string) string {
a = a[0:strings.Index(a, "/")]
if a == "image" || a == "video" {
err := os.WriteFile(Conf.Cache.Path+"/"+encsum, []byte(body), 0700)
if err != nil {
fmt.Println(err)
}
Err(err)
return string(body)
}
@ -85,9 +81,7 @@ func Cache(img string) string {
}
} else {
file, err := io.ReadAll(file)
if err != nil {
println(err)
}
Err(err)
return string(file)
}
file.Close()

View File

@ -2,7 +2,6 @@ package util
import (
"encoding/json"
"fmt"
"log"
"os"
)
@ -14,18 +13,17 @@ type cconf struct {
}
type c struct {
Listen string
Cache cconf
Proxy, Nsfw bool
Listen, Base_uri string
Cache cconf
Proxy, Nsfw bool
}
var Conf = c{
Listen: "127.0.0.1:3003",
Listen: "127.0.0.1:3003",
Base_uri: "/",
Cache: cconf{
Enabled: true,
Path: "cache",
// Max_size: 4000000,
// Lifetime: 10000,
},
Proxy: true,
Nsfw: true,
@ -39,7 +37,7 @@ func ParseConfig() {
a = a[2:]
switch a {
case "help":
println(`SkunkyArt v1.0 Beta
println(`SkunkyArt v1.2
Usage:
- config: specify config file path;
- help: prints this message.
@ -51,7 +49,7 @@ lost+skunk, 2024. Source Code: https://git.macaw.me/skunky/skunkyart`)
case "config":
file, err := os.ReadFile(os.Args[b+1])
if err != nil {
log.Fatalln(fmt.Sprint(err))
log.Fatalln(err.Error())
}
if len(file) > 0 {
@ -67,7 +65,7 @@ lost+skunk, 2024. Source Code: https://git.macaw.me/skunky/skunkyart`)
file, err := os.ReadFile(cfile)
if err != nil {
panic(fmt.Sprintln(err))
panic(err.Error())
}
json.Unmarshal(file, &Conf)

View File

@ -80,7 +80,10 @@ func Images(deviation Deviation, media Media, nfmt bool) string {
}
if nfmt {
return "/image/" + image
if image == "" {
return "no"
}
return Conf.Base_uri + "image/" + image
}
var link string
@ -94,7 +97,7 @@ func Images(deviation Deviation, media Media, nfmt bool) string {
}
if image != "" {
image = "<img src=\"/image/" + image + "\" width=\"15%\">"
image = "<img src=\"" + Conf.Base_uri + "image/" + image + "\" width=\"15%\">"
} else {
image = "<h1>[ TEXT ]</h1>"
}
@ -111,5 +114,5 @@ func Images(deviation Deviation, media Media, nfmt bool) string {
deviation.Title += " [<span class=\"nsfw\">NSFW</span>]"
}
return "<div class=\"block\">" + image + "<br><a href=\"/post" + link + "\">" + deviation.Author.Username + deviation.Title + "</a></div>"
return "<div class=\"block\">" + image + "<br><a href=\"" + Conf.Base_uri + "post" + link + "\">" + deviation.Author.Username + deviation.Title + "</a></div>"
}

View File

@ -2,9 +2,10 @@ package util
import (
"bytes"
"fmt"
"io"
"net/http"
"strings"
"text/template"
"golang.org/x/net/html"
)
@ -15,23 +16,32 @@ func Request(url string, cookie string) (string, int, []*http.Cookie, http.Heade
request, err := http.NewRequest("GET", url, nil)
request.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0.0")
request.Header.Set("Cookie", cookie)
if err != nil {
fmt.Println(err)
}
Err(err)
response, err := cli.Do(request)
if err != nil {
fmt.Println(err)
}
Err(err)
body, err := io.ReadAll(response.Body)
if err != nil {
fmt.Println(err)
}
Err(err)
response.Body.Close()
return string(body), response.StatusCode, response.Cookies(), response.Header
}
func TmpExec(file string, templatee any) string {
var buf bytes.Buffer
tmpl, err := template.ParseFiles(file)
Err(err)
tmpl.Execute(&buf, &templatee)
return strings.ReplaceAll(buf.String(), "!BAZE!", "<base href=\""+Conf.Base_uri+"\">")
}
func Render(n *html.Node) string {
var buffer bytes.Buffer
html.Render(io.Writer(&buffer), n)
return buffer.String()
}
func Err(err error) {
if err != nil {
println(err.Error())
}
}

View File

@ -37,7 +37,7 @@ func Parse(n string) string {
switch a.Key {
case "src":
if a.Val[8:9] == "e" {
uri = "/emoji/" + a.Val[37:len(a.Val)-4]
uri = Conf.Base_uri + "emoji/" + a.Val[37:len(a.Val)-4]
}
case "title":
title = a.Val