diff --git a/app/router.go b/app/router.go index 9e51fd9..d98e2a9 100644 --- a/app/router.go +++ b/app/router.go @@ -52,7 +52,7 @@ func Router() { // пути switch e { default: - skunky.httperr(404) + skunky.ReturnHTTPError(404) case "/", "": open_n_send("html/index.htm") case "post": @@ -62,7 +62,7 @@ func Router() { skunky.Search() case "dd": skunky.DD() - case "group": + case "group_user": skunky.GRUser() case "media": diff --git a/app/util.go b/app/util.go index 7c4d104..e4a1de2 100644 --- a/app/util.go +++ b/app/util.go @@ -2,11 +2,38 @@ package app import ( "encoding/json" + "net/http" + "strconv" "strings" + "text/template" "git.macaw.me/skunky/devianter" ) +// парсинг темплейтов +func (s skunkyart) ExecuteTemplate(file string, data any) { + var buf strings.Builder + tmp, e := template.ParseFiles(file) + err(e) + err(tmp.Execute(&buf, &data)) + wr(s.Writer, buf.String()) +} + +func (s skunkyart) ReturnHTTPError(status int) { + s.Writer.WriteHeader(status) + + // пострйока с помощью strings.Builder, потому что такой метод быстрее обычного сложения + var msg strings.Builder + msg.WriteString(``) + msg.WriteString("

") + msg.WriteString(strconv.Itoa(status)) + msg.WriteString(" - ") + msg.WriteString(http.StatusText(status)) + msg.WriteString("

") + + wr(s.Writer, msg.String()) +} + type text struct { TXT string from int @@ -87,3 +114,174 @@ func ParseDescription(dscr devianter.Text) string { return parseddescription.String() } + +// навигация по страницам +type dlist struct { + Pages int + More bool +} + +// FIXME: на некоротрых артах первая страница может вызывать полное отсутствие панели навигации. +func (s skunkyart) NavBase(c dlist) string { + // TODO: сделать понятнее + // навигация по страницам + var list strings.Builder + list.WriteString("
") + p := s.Page + + // функция для генерации ссылок + prevrev := func(msg string, page int, onpage bool) { + if !onpage { + list.WriteString(``) + list.WriteString(msg) + list.WriteString(" ") + } else { + list.WriteString(strconv.Itoa(page)) + list.WriteString(" ") + } + } + + // вперёд-назад + if p > 1 { + prevrev("<= Prev |", p-1, false) + } else { + p = 1 + } + + if c.Pages > 0 { + // назад + for x := p - 6; x < p && x > 0; x++ { + prevrev(strconv.Itoa(x), x, false) + } + + // вперёд + for x := p; x <= p+6; x++ { + if x == p { + prevrev("", x, true) + x++ + } + + if x > p { + prevrev(strconv.Itoa(x), x, false) + } + } + } + + // вперёд-назад + if c.More { + prevrev("| Next =>", p+1, false) + } + + return list.String() +} + +func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) string { + var list strings.Builder + list.WriteString(`
`) + for _, data := range devs { + url := devianter.UrlFromMedia(data.Media) + + list.WriteString(`

`) + list.WriteString(data.Author.Username) + list.WriteString(" - ") + list.WriteString(data.Title) + + // шильдики нсфв, аи и ежедневного поста + if data.NSFW { + list.WriteString(` [NSFW]`) + } + if data.AI { + list.WriteString(" [🤖]") + } + if data.DD { + list.WriteString(` [DD]`) + } + + list.WriteString("
") + } + list.WriteString("
") + list.WriteString(s.NavBase(content[0])) + + return list.String() +} + +// FIXME: первый комментарий не отображается. +func (s skunkyart) ParseComments(c devianter.Comments) string { + var cmmts strings.Builder + replied := make(map[int]string) + + cmmts.WriteString("
Comments: ") + cmmts.WriteString(strconv.Itoa(c.Total)) + cmmts.WriteString("") + for _, x := range c.Thread { + replied[x.ID] = x.User.Username + cmmts.WriteString(`

`) + cmmts.WriteString(x.User.Username) + cmmts.WriteString(" ") + + if x.Parent > 0 { + cmmts.WriteString(` In reply to `) + if replied[x.Parent] == "" { + cmmts.WriteString("???") + } else { + cmmts.WriteString(replied[x.Parent]) + } + cmmts.WriteString("") + } + cmmts.WriteString(" [") + cmmts.WriteString(x.Posted.UTC().String()) + cmmts.WriteString("]

") + + cmmts.WriteString(x.Comment) + cmmts.WriteString("

👍: ") + cmmts.WriteString(strconv.Itoa(x.Likes)) + cmmts.WriteString(" ⏩: ") + cmmts.WriteString(strconv.Itoa(x.Replies)) + cmmts.WriteString("

\n") + } + cmmts.WriteString(s.NavBase(dlist{ + Pages: 0, + More: c.HasMore, + })) + cmmts.WriteString("
") + return cmmts.String() +} diff --git a/app/wraper.go b/app/wraper.go index ccaccee..2b733fd 100644 --- a/app/wraper.go +++ b/app/wraper.go @@ -1,14 +1,13 @@ package app import ( - "bytes" + "fmt" "io" "net/http" "net/url" "regexp" "strconv" "strings" - "text/template" "time" "git.macaw.me/skunky/devianter" @@ -17,206 +16,108 @@ import ( var wr = io.WriteString type skunkyart struct { - Writer http.ResponseWriter - Args url.Values - Type rune - Query string - Page int -} + Writer http.ResponseWriter + Args url.Values + Type rune + Query string + Page int + Templates struct { + GroupUser struct { + GR devianter.GRuser + CreationDate string -// парсинг темплейтов -func (s skunkyart) exe(file string, data any) { - var buf bytes.Buffer - tmp, e := template.ParseFiles(file) - err(e) - tmp.Execute(&buf, &data) - wr(s.Writer, buf.String()) -} + About struct { + A devianter.About -func (s skunkyart) httperr(status int) { - s.Writer.WriteHeader(status) - - // пострйока с помощью strings.Builder, потому что такой метод быстрее обычного сложения - var msg strings.Builder - msg.WriteString(``) - msg.WriteString("

") - msg.WriteString(strconv.Itoa(status)) - msg.WriteString(" - ") - msg.WriteString(http.StatusText(status)) - msg.WriteString("

") - - wr(s.Writer, msg.String()) -} - -// навигация по страницам -type dlist struct { - Pages int - More bool -} - -// FIXME: на некоротрых артах первая страница может вызывать полное отсутствие панели навигации. -func (s skunkyart) NavBase(c dlist) string { - // TODO: сделать понятнее - // навигация по страницам - var list strings.Builder - list.WriteString("
") - p := s.Page - - // функция для генерации ссылок - prevrev := func(msg string, page int, onpage bool) { - if !onpage { - list.WriteString(``) - list.WriteString(msg) - list.WriteString(" ") - } else { - list.WriteString(strconv.Itoa(page)) - list.WriteString(" ") - } - } - - // вперёд-назад - if p > 1 { - prevrev("<= Prev |", p-1, false) - } else { - p = 1 - } - - if c.Pages > 0 { - // назад - for x := p - 6; x < p && x > 0; x++ { - prevrev(strconv.Itoa(x), x, false) - } - - // вперёд - for x := p; x <= p+6; x++ { - if x == p { - prevrev("", x, true) - x++ + DescriptionFormatted string + Interests, Social string + Comments string + BG string + BGMeta devianter.Deviation } - if x > p { - prevrev(strconv.Itoa(x), x, false) + Gallery struct { + Pages int + List string } } + Search struct { + Content devianter.Search + List string + } } - - // вперёд-назад - if c.More { - prevrev("| Next =>", p+1, false) - } - - return list.String() } func (s skunkyart) GRUser() { - var group struct { - GR devianter.GRuser - CreationDate string - - About struct { - A devianter.About - - DescriptionFormatted string - Interests string - Social string - BG devianter.Deviation - } - } - if len(s.Query) < 1 { - s.httperr(400) + s.ReturnHTTPError(400) return } var g devianter.Group g.Name = s.Query - group.GR = g.GroupFunc() + s.Templates.GroupUser.GR = g.GroupFunc() + group := &s.Templates.GroupUser - if g := group.GR; !g.Owner.Group { - for _, x := range g.Gruser.Page.Modules { - var about = group.About.A - if x.ModuleData.About.RegDate != 0 { - about = x.ModuleData.About - } - group.About.DescriptionFormatted = ParseDescription(about.Description) + switch s.Type { + case 'a': + if g := group.GR; !g.Owner.Group { + for _, x := range g.Gruser.Page.Modules { + switch x.Name { + case "about": + group.About.A = x.ModuleData.About + var about = group.About.A + group.About.DescriptionFormatted = ParseDescription(about.Description) + group.About.Comments = s.ParseComments(devianter.CommentsFunc( + strconv.Itoa(group.GR.Gruser.ID), + "", + s.Page, + 4, + )) - for _, val := range x.ModuleData.About.Interests { - var interest strings.Builder - interest.WriteString(val.Label) - interest.WriteString(": ") - interest.WriteString(val.Value) - interest.WriteString("
") - group.About.Interests += interest.String() - } + for _, val := range x.ModuleData.About.SocialLinks { + var social strings.Builder + social.WriteString(``) + social.WriteString(val.Value) + social.WriteString("
") + group.About.Social += social.String() + } - for _, val := range x.ModuleData.About.SocialLinks { - var social strings.Builder - social.WriteString(``) - social.WriteString(val.Value) - social.WriteString("
") - group.About.Social += social.String() - } + for _, val := range x.ModuleData.About.Interests { + var interest strings.Builder + interest.WriteString(val.Label) + interest.WriteString(": ") + interest.WriteString(val.Value) + interest.WriteString("
") + group.About.Interests += interest.String() + } - if rd := x.ModuleData.About.RegDate; rd != 0 { - group.CreationDate = time.Unix(time.Now().Unix()-rd, 0).UTC().String() + if rd := x.ModuleData.About.RegDate; rd != 0 { + group.CreationDate = time.Unix(time.Now().Unix()-rd, 0).UTC().String() + } + case "cover_deviation": + group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation + group.About.BG = devianter.UrlFromMedia(group.About.BGMeta.Media) + } } + } else { + } - } else { - + case 'g': + gallery := g.Gallery(s.Page) + fmt.Println(gallery) + for _, x := range gallery.Content.Gruser.Page.Modules { + group.Gallery.List = s.DeviationList(x.ModuleData.Folder.Deviations, dlist{ + Pages: x.ModuleData.Folder.Pages, + }) + } + default: + s.ReturnHTTPError(400) } - s.exe("html/gruser.htm", &group) -} - -func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) string { - var list strings.Builder - list.WriteString(`
`) - for _, data := range devs { - url := devianter.UrlFromMedia(data.Media) - - list.WriteString(`

`) - list.WriteString(data.Author.Username) - list.WriteString(" - ") - list.WriteString(data.Title) - - // шильдики нсфв, аи и ежедневного поста - if data.NSFW { - list.WriteString(` [NSFW]`) - } - if data.AI { - list.WriteString(" [🤖]") - } - if data.DD { - list.WriteString(` [DD]`) - } - - list.WriteString("
") - } - list.WriteString("
") - list.WriteString(s.NavBase(content[0])) - - return list.String() + s.ExecuteTemplate("html/gruser.htm", &s) } // посты @@ -250,115 +151,52 @@ func (s skunkyart) Deviation(author, postname string) { post.Tags += tag.String() } - // FIXME: первый комментарий не отображается. - // генерация комментов - var cmmts strings.Builder - replied := make(map[int]string) - c := devianter.CommentsFunc(id, post.Post.Comments.Cursor, s.Page, 1) + post.Comments = s.ParseComments(devianter.CommentsFunc(id, post.Post.Comments.Cursor, s.Page, 1)) - cmmts.WriteString("
Comments: ") - cmmts.WriteString(strconv.Itoa(c.Total)) - cmmts.WriteString("") - for _, x := range c.Thread { - replied[x.ID] = x.User.Username - cmmts.WriteString(`

`) - cmmts.WriteString(x.User.Username) - cmmts.WriteString(" ") - - if x.Parent > 0 { - cmmts.WriteString(` In reply to `) - if replied[x.Parent] == "" { - cmmts.WriteString("???") - } else { - cmmts.WriteString(replied[x.Parent]) - } - cmmts.WriteString("") - } - cmmts.WriteString(" [") - cmmts.WriteString(x.Posted.UTC().String()) - cmmts.WriteString("]

") - - cmmts.WriteString(x.Comment) - cmmts.WriteString("

👍: ") - cmmts.WriteString(strconv.Itoa(x.Likes)) - cmmts.WriteString(" ⏩: ") - cmmts.WriteString(strconv.Itoa(x.Replies)) - cmmts.WriteString("

\n") - } - cmmts.WriteString(s.NavBase(dlist{ - Pages: 0, - More: c.HasMore, - })) - cmmts.WriteString("
") - - post.Comments = cmmts.String() - - s.exe("html/deviantion.htm", &post) + s.ExecuteTemplate("html/deviantion.htm", &post) } else { - s.httperr(400) + s.ReturnHTTPError(400) } } func (s skunkyart) DD() { dd := devianter.DailyDeviationsFunc(s.Page) - s.exe("html/list.htm", s.DeviationList(dd.Deviations, dlist{ + s.ExecuteTemplate("html/list.htm", s.DeviationList(dd.Deviations, dlist{ Pages: 0, More: dd.HasMore, })) } func (s skunkyart) Search() { - // тут всё и так понятно + var e error + ss := &s.Templates.Search switch s.Type { - case 'a', 't', 'g': - var srch struct { - Search devianter.Search - List string - } - - var e error - srch.Search, e = devianter.SearchFunc(s.Query, s.Page, s.Type) - err(e) - srch.List = s.DeviationList(srch.Search.Results, dlist{ - Pages: srch.Search.Pages, - More: srch.Search.HasMore, - }) - - s.exe("html/search.htm", &srch) + case 'a', 't': + ss.Content, e = devianter.SearchFunc(s.Query, s.Page, s.Type) + case 'g': + ss.Content, e = devianter.SearchFunc(s.Query, s.Page, s.Type, s.Args.Get("usr")) default: - s.httperr(400) + s.ReturnHTTPError(400) } + err(e) + + ss.List = s.DeviationList(ss.Content.Results, dlist{ + Pages: ss.Content.Pages, + More: ss.Content.HasMore, + }) + + s.ExecuteTemplate("html/search.htm", &s) } 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.httperr(404) + s.ReturnHTTPError(404) println(e.Error()) } wr(s.Writer, ae) } else { - s.httperr(400) + s.ReturnHTTPError(400) } } diff --git a/css/skunky.css b/css/skunky.css index 95e7984..9c00522 100644 --- a/css/skunky.css +++ b/css/skunky.css @@ -83,4 +83,11 @@ form input, button, select { .block p { word-break: break-all; } - +.ubg { + display: flex; + flex-wrap: wrap; + justify-content: center; +} +.ubg img { + width: 20%; +} diff --git a/html/deviantion.htm b/html/deviantion.htm index 75484f6..6308c91 100644 --- a/html/deviantion.htm +++ b/html/deviantion.htm @@ -18,7 +18,7 @@
- {{.Post.Deviation.Author.Username}} — {{if (.Post.Deviation.DD)}} + {{.Post.Deviation.Author.Username}} — {{if (.Post.Deviation.DD)}} {{.Post.Deviation.Title}} {{else}}{{.Post.Deviation.Title}}{{end}} {{if (ne .Post.Deviation.License "none")}}{{.Post.Deviation.License}}{{end}} {{if (.Post.Deviation.AI)}}[🤖]{{end}} diff --git a/html/gruser.htm b/html/gruser.htm index b81ceb1..5a5c801 100644 --- a/html/gruser.htm +++ b/html/gruser.htm @@ -1,43 +1,74 @@ - SkunkyArt | {{.GR.Owner.Username}} + SkunkyArt | + {{if eq .Type 'a'}} + {{.Templates.GroupUser.GR.Owner.Username}} + {{else}} + gallery of {{.Templates.GroupUser.GR.Owner.Username}} + {{end}} +
-

HOME | DD

-
- +

HOME | DD + | Gallery

{{else}}about">About + {{end}} + + +
- {{.GR.Owner.Username}} - {{if (eq .About.A.Gender "male")}} - ♂️ + {{if eq .Type 'a'}} + {{if ne .Templates.GroupUser.About.BG ""}} + + {{end}} + + {{.Templates.GroupUser.GR.Owner.Username}} + {{if (eq .Templates.GroupUser.About.A.Gender "male")}} + ♂️ + {{end}} + {{if (eq .Templates.GroupUser.About.A.Gender "female")}} + ♀️ + {{end}} + [{{.Templates.GroupUser.GR.Gruser.ID}}] + [{{.Templates.GroupUser.CreationDate}}] + {{if ne .Templates.GroupUser.GR.Extra.Tag ""}} + "{{.Templates.GroupUser.GR.Extra.Tag}}"{{end}} ({{.Templates.GroupUser.About.A.Country}}) + +

# Statistics

+

Favourites: {{.Templates.GroupUser.GR.Extra.Stats.Favourites}}; Deviations: {{.Templates.GroupUser.GR.Extra.Stats.Deviations}}; Watchers: {{.Templates.GroupUser.GR.Extra.Stats.Watchers}} +

Watching: {{.Templates.GroupUser.GR.Extra.Stats.Watching}}; Pageviews: {{.Templates.GroupUser.GR.Extra.Stats.Pageviews}}; Comments Made: {{.Templates.GroupUser.GR.Extra.Stats.CommentsMade}}; Friends: {{.Templates.GroupUser.GR.Extra.Stats.Friends}}

+ + {{if ne .Templates.GroupUser.About.Interests ""}} +

# Interests

+ {{.Templates.GroupUser.About.Interests}} + {{end}} + + {{if ne .Templates.GroupUser.About.Social ""}} +

# Social Links

+ {{.Templates.GroupUser.About.Social}} + {{end}} + + {{if ne .Templates.GroupUser.About.DescriptionFormatted ""}} +

# About me

+ {{.Templates.GroupUser.About.DescriptionFormatted}} + {{end}} + {{if ne .Templates.GroupUser.About.Comments ""}} +
+

# Comments

+ {{.Templates.GroupUser.About.Comments}} + {{end}} + {{else}} + {{.Templates.GroupUser.Gallery.List}} {{end}} - {{if (eq .About.A.Gender "female")}} - ♀️ - {{end}} - [{{.GR.Gruser.ID}}] - [{{.CreationDate}}] - "{{.GR.Extra.Tag}}" - -

# Statistics

-

Favourites: {{.GR.Extra.Stats.Favourites}}; Deviations: {{.GR.Extra.Stats.Deviations}}; Watchers: {{.GR.Extra.Stats.Watchers}} -

Watching: {{.GR.Extra.Stats.Watching}}; Pageviews: {{.GR.Extra.Stats.Pageviews}}; Comments Made: {{.GR.Extra.Stats.CommentsMade}}; Friends: {{.GR.Extra.Stats.Friends}}

- -

# Interests

- {{.About.Interests}} - -

# Social Links

- {{.About.Social}} - -

# About me

- {{.About.DescriptionFormatted}}
- \ No newline at end of file + diff --git a/html/search.htm b/html/search.htm index 8ab9438..a78feb6 100644 --- a/html/search.htm +++ b/html/search.htm @@ -1,7 +1,7 @@ - SkunkyArt | Search + SkunkyArt | Search "{{.Query}}"
@@ -16,11 +16,11 @@ - {{if (ne .List "")}} - {{if (ne .Search.Total 0)}} -

Total resuls: {{.Search.Total}}

+ {{if ne .Templates.Search.List ""}} + {{if ne .Templates.Search.Content.Total 0}} +

Total resuls: {{.Templates.Search.Content.Total}}

{{end}} - {{.List}} + {{.Templates.Search.List}} {{else}}

No results :(

{{end}}