From ff4f1a2422b3e02917af1f1786ff5b3ac09565ef Mon Sep 17 00:00:00 2001 From: lost+skunk Date: Sat, 6 Jul 2024 20:06:04 +0300 Subject: Реки и копирование темплейтов в озу MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/config.go | 32 +++--- app/util.go | 41 ++++++-- app/wraper.go | 290 ---------------------------------------------------- app/wrapper.go | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++ config.example.json | 8 +- html/deviantion.htm | 6 ++ html/search.htm | 2 +- main.go | 1 + 8 files changed, 350 insertions(+), 315 deletions(-) delete mode 100644 app/wraper.go create mode 100644 app/wrapper.go diff --git a/app/config.go b/app/config.go index 1df6aaf..18cea29 100644 --- a/app/config.go +++ b/app/config.go @@ -7,19 +7,21 @@ import ( ) type cache_config struct { - Enabled bool - Path string - MaxSize int64 `json:"max-size"` - Lifetime int64 + Enabled bool + Path string + MaxSize int64 `json:"max-size"` + Lifetime int64 + UpdateInterval int64 `json:"update-interval"` } type config struct { - cfg string - Listen string - BasePath string `json:"base-path"` - Cache cache_config - Proxy, Nsfw bool - WixmpProxy string `json:"wixmp-proxy"` + cfg string + Listen string + BasePath string `json:"base-path"` + Cache cache_config + Proxy, Nsfw bool + WixmpProxy string `json:"wixmp-proxy"` + TemplatesDir string `json:"templates-dir"` } var CFG = config{ @@ -27,11 +29,13 @@ var CFG = config{ Listen: "127.0.0.1:3003", BasePath: "/", Cache: cache_config{ - Enabled: true, - Path: "cache", + Enabled: true, + Path: "cache", + UpdateInterval: 1, }, - Proxy: true, - Nsfw: true, + TemplatesDir: "html", + Proxy: true, + Nsfw: true, } func ExecuteConfig() { diff --git a/app/util.go b/app/util.go index 9e1784d..e22e83b 100644 --- a/app/util.go +++ b/app/util.go @@ -19,7 +19,8 @@ import ( // парсинг темплейтов func (s skunkyart) ExecuteTemplate(file string, data any) { var buf strings.Builder - tmp, e := template.ParseFiles(file) + tmp := template.New(file) + tmp, e := tmp.Parse(Templates[file]) err(e) err(tmp.Execute(&buf, &data)) wr(s.Writer, buf.String()) @@ -57,7 +58,9 @@ 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:]) + if toart != -1 { + output = UrlBuilder("post", url[:toart], url[toart+5:]) + } } return } @@ -261,7 +264,7 @@ func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) s if url != "" { list.WriteString(``) } else { @@ -296,7 +299,9 @@ func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) s return "" } else { list.WriteString("") - list.WriteString(s.NavBase(content[0])) + if content != nil { + list.WriteString(s.NavBase(content[0])) + } } return list.String() @@ -425,6 +430,7 @@ func (s skunkyart) DownloadAndSendMedia(subdomain, path string) { b, _, _ := download() s.Writer.Write(b) } else { + s.Writer.WriteHeader(403) s.Writer.Write([]byte("Sorry, butt proxy on this instance disabled.")) } } @@ -441,6 +447,9 @@ func InitCacheSystem() { err(e) for _, a := range dirnames { a = c.Path + "/" + a + rm := func() { + err(os.RemoveAll(a)) + } if c.Lifetime != 0 { now := time.Now().UnixMilli() @@ -449,15 +458,33 @@ func InitCacheSystem() { time := time.Unix(stat.Ctim.Unix()).UnixMilli() if time+c.Lifetime <= now { - os.RemoveAll(a) + rm() } } if c.MaxSize != 0 && stat.Size() > c.MaxSize { - os.RemoveAll(a) + rm() } } dir.Close() - time.Sleep(time.Second) + time.Sleep(time.Second * time.Duration(CFG.Cache.UpdateInterval)) + } +} + +func CopyTemplatesToMemory() { + try := func(e error) { + if e != nil { + panic(e.Error()) + } + } + + dir, e := os.ReadDir(CFG.TemplatesDir) + try(e) + + for _, x := range dir { + n := CFG.TemplatesDir + "/" + x.Name() + file, e := os.ReadFile(n) + try(e) + Templates[n] = string(file) } } diff --git a/app/wraper.go b/app/wraper.go deleted file mode 100644 index f42a9af..0000000 --- a/app/wraper.go +++ /dev/null @@ -1,290 +0,0 @@ -package app - -import ( - "io" - "net/http" - "net/url" - "regexp" - "strconv" - "strings" - "time" - - "git.macaw.me/skunky/devianter" -) - -var wr = io.WriteString - -type skunkyart struct { - Writer http.ResponseWriter - Args url.Values - BasePath string - Type rune - Query, QueryRaw string - Page int - 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 { - GR devianter.GRuser - Admins string - Group bool - CreationDate string - - About struct { - A devianter.About - - DescriptionFormatted string - Interests, Social string - Comments string - BG string - BGMeta devianter.Deviation - } - - Gallery struct { - Folders string - Pages int - List string - } - } - Search struct { - Content devianter.Search - List string - } - } -} - -// 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() { - if len(s.Query) < 1 { - s.ReturnHTTPError(400) - return - } - - var g devianter.Group - g.Name = s.Query - s.Templates.GroupUser.GR = g.GroupFunc() - group := &s.Templates.GroupUser - - switch s.Type { - case 'a': - g := group.GR - s.Atom = false - for _, x := range g.Gruser.Page.Modules { - switch x.Name { - case "about", "group_about": - switch g.Owner.Group { - case true: - var about = &x.ModuleData.GroupAbout - group.Group = true - group.CreationDate = x.ModuleData.GroupAbout.FoundatedAt.UTC().String() - group.About.DescriptionFormatted = ParseDescription(about.Description) - case false: - group.About.A = x.ModuleData.About - var about = &group.About.A - group.CreationDate = time.Unix(time.Now().Unix()-x.ModuleData.About.RegDate, 0).UTC().String() - - group.About.DescriptionFormatted = ParseDescription(about.Description) - - 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() - } - } - group.About.Comments = s.ParseComments(devianter.CommentsFunc( - strconv.Itoa(group.GR.Gruser.ID), - "", - s.Page, - 4, - )) - - case "cover_deviation": - group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation - group.About.BGMeta.Url = s.ConvertDeviantArtUrlToSkunkyArt(group.About.BGMeta.Url) - group.About.BG = s.ParseMedia(group.About.BGMeta.Media) - case "group_admins": - var htm strings.Builder - for _, z := range x.ModuleData.GroupAdmins.Results { - htm.WriteString(`

`) - htm.WriteString(z.User.Username) - htm.WriteString(`

`) - } - group.Admins += htm.String() - } - - } - case 'g': - folderid, _ := strconv.Atoi(s.Args.Get("folder")) - if s.Page == 0 { - s.Page++ - } - - gallery := g.Gallery(s.Page, folderid) - if folderid > 0 { - group.Gallery.List = s.DeviationList(gallery.Content.Results, dlist{ - More: gallery.Content.HasMore, - }) - } else { - for _, x := range gallery.Content.Gruser.Page.Modules { - if l := len(x.ModuleData.Folders.Results); l != 0 { - var folders strings.Builder - folders.WriteString(`

Folders: `) - for n, x := range x.ModuleData.Folders.Results { - folders.WriteString(``) - folders.WriteString(x.Name) - folders.WriteString(``) - if n+1 < l { - folders.WriteString(" | ") - } - } - folders.WriteString("

") - group.Gallery.Folders = folders.String() - } - - if x.Name == "folder_deviations" { - group.Gallery.List = s.DeviationList(x.ModuleData.Folder.Deviations, dlist{ - Pages: x.ModuleData.Folder.Pages, - More: x.ModuleData.Folder.HasMore, - }) - } - } - } - default: - s.ReturnHTTPError(400) - } - - if !s.Atom { - s.ExecuteTemplate("html/gruser.htm", &s) - } -} - -// посты -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.DeviationFunc(id, author) - - post.Post.Description = ParseDescription(post.Post.Deviation.TextContent) - // время публикации - post.StringTime = post.Post.Deviation.PublishedTime.UTC().String() - - // хештэги - for _, x := range post.Post.Deviation.Extended.Tags { - var tag strings.Builder - tag.WriteString(` #`) - tag.WriteString(x.Name) - tag.WriteString("") - - post.Tags += tag.String() - } - - post.Comments = s.ParseComments(devianter.CommentsFunc(id, post.Post.Comments.Cursor, s.Page, 1)) - - s.ExecuteTemplate("html/deviantion.htm", &s) - } else { - s.ReturnHTTPError(400) - } -} - -func (s skunkyart) DD() { - dd := devianter.DailyDeviationsFunc(s.Page) - s.Templates.SomeList = s.DeviationList(dd.Deviations, dlist{ - Pages: 0, - More: dd.HasMore, - }) - if !s.Atom { - s.ExecuteTemplate("html/list.htm", &s) - } -} - -func (s skunkyart) Search() { - s.Atom = false - var e error - ss := &s.Templates.Search - switch s.Type { - 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.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.ReturnHTTPError(404) - } - wr(s.Writer, ae) - } else { - 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) -} diff --git a/app/wrapper.go b/app/wrapper.go new file mode 100644 index 0000000..006a02a --- /dev/null +++ b/app/wrapper.go @@ -0,0 +1,285 @@ +package app + +import ( + "io" + "net/http" + "net/url" + "regexp" + "strconv" + "strings" + "time" + + "git.macaw.me/skunky/devianter" +) + +var wr = io.WriteString +var Templates = make(map[string]string) + +type skunkyart struct { + Writer http.ResponseWriter + Args url.Values + BasePath string + Type rune + Query, QueryRaw string + Page int + Atom bool + Templates struct { + About struct { + Proxy bool + Nsfw bool + } + + SomeList string + Deviation struct { + Post devianter.Post + Related string + StringTime string + Tags string + Comments string + } + + GroupUser struct { + GR devianter.GRuser + Admins string + Group bool + CreationDate string + + About struct { + A devianter.About + + DescriptionFormatted string + Interests, Social string + Comments string + BG string + BGMeta devianter.Deviation + } + + Gallery struct { + Folders string + Pages int + List string + } + } + Search struct { + Content devianter.Search + List string + } + } +} + +func (s skunkyart) GRUser() { + if len(s.Query) < 1 { + s.ReturnHTTPError(400) + return + } + + var g devianter.Group + g.Name = s.Query + s.Templates.GroupUser.GR = g.GroupFunc() + group := &s.Templates.GroupUser + + switch s.Type { + case 'a': + g := group.GR + s.Atom = false + for _, x := range g.Gruser.Page.Modules { + switch x.Name { + case "about", "group_about": + switch g.Owner.Group { + case true: + var about = &x.ModuleData.GroupAbout + group.Group = true + group.CreationDate = x.ModuleData.GroupAbout.FoundatedAt.UTC().String() + group.About.DescriptionFormatted = ParseDescription(about.Description) + case false: + group.About.A = x.ModuleData.About + var about = &group.About.A + group.CreationDate = time.Unix(time.Now().Unix()-x.ModuleData.About.RegDate, 0).UTC().String() + + group.About.DescriptionFormatted = ParseDescription(about.Description) + + 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() + } + } + group.About.Comments = s.ParseComments(devianter.CommentsFunc( + strconv.Itoa(group.GR.Gruser.ID), + "", + s.Page, + 4, + )) + + case "cover_deviation": + group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation + group.About.BGMeta.Url = s.ConvertDeviantArtUrlToSkunkyArt(group.About.BGMeta.Url) + group.About.BG = s.ParseMedia(group.About.BGMeta.Media) + case "group_admins": + var htm strings.Builder + for _, z := range x.ModuleData.GroupAdmins.Results { + htm.WriteString(`

`) + htm.WriteString(z.User.Username) + htm.WriteString(`

`) + } + group.Admins += htm.String() + } + + } + case 'g': + folderid, _ := strconv.Atoi(s.Args.Get("folder")) + if s.Page == 0 { + s.Page++ + } + + gallery := g.Gallery(s.Page, folderid) + if folderid > 0 { + group.Gallery.List = s.DeviationList(gallery.Content.Results, dlist{ + More: gallery.Content.HasMore, + }) + } else { + for _, x := range gallery.Content.Gruser.Page.Modules { + if l := len(x.ModuleData.Folders.Results); l != 0 { + var folders strings.Builder + folders.WriteString(`

Folders: `) + for n, x := range x.ModuleData.Folders.Results { + folders.WriteString(``) + folders.WriteString(x.Name) + folders.WriteString(``) + if n+1 < l { + folders.WriteString(" | ") + } + } + folders.WriteString("

") + group.Gallery.Folders = folders.String() + } + + if x.Name == "folder_deviations" { + group.Gallery.List = s.DeviationList(x.ModuleData.Folder.Deviations, dlist{ + Pages: x.ModuleData.Folder.Pages, + More: x.ModuleData.Folder.HasMore, + }) + } + } + } + default: + s.ReturnHTTPError(400) + } + + if !s.Atom { + s.ExecuteTemplate("html/gruser.htm", &s) + } +} + +// посты +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.DeviationFunc(id, author) + + post.Post.Description = ParseDescription(post.Post.Deviation.TextContent) + // время публикации + post.StringTime = post.Post.Deviation.PublishedTime.UTC().String() + post.Post.IMG = s.ParseMedia(post.Post.Deviation.Media) + for _, x := range post.Post.Deviation.Extended.RelatedContent { + if len(x.Deviations) != 0 { + post.Related = s.DeviationList(x.Deviations) + } + } + + // хештэги + for _, x := range post.Post.Deviation.Extended.Tags { + var tag strings.Builder + tag.WriteString(` #`) + tag.WriteString(x.Name) + tag.WriteString("") + + post.Tags += tag.String() + } + + post.Comments = s.ParseComments(devianter.CommentsFunc(id, post.Post.Comments.Cursor, s.Page, 1)) + + s.ExecuteTemplate("html/deviantion.htm", &s) + } else { + s.ReturnHTTPError(400) + } +} + +func (s skunkyart) DD() { + dd := devianter.DailyDeviationsFunc(s.Page) + s.Templates.SomeList = s.DeviationList(dd.Deviations, dlist{ + Pages: 0, + More: dd.HasMore, + }) + if !s.Atom { + s.ExecuteTemplate("html/list.htm", &s) + } +} + +func (s skunkyart) Search() { + s.Atom = false + var e error + ss := &s.Templates.Search + switch s.Type { + 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.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.ReturnHTTPError(404) + } + wr(s.Writer, ae) + } else { + 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) +} diff --git a/config.example.json b/config.example.json index 56b5218..2c3205d 100644 --- a/config.example.json +++ b/config.example.json @@ -1,13 +1,15 @@ { "listen": "0.0.0.0:3003", - "base-path": "/skunky/", + "base-path": "/", "cache": { "enabled": true, "path": "cache", "lifetime": null, - "max-size": 100000 + "max-size": 100000, + "update-interval": 5 }, - "proxy": true, + "templates-dir": "html", "wixmp-proxy": "http://127.0.0.1:8080", + "proxy": true, "nsfw": false } \ No newline at end of file diff --git a/html/deviantion.htm b/html/deviantion.htm index 7a7f282..97850d3 100644 --- a/html/deviantion.htm +++ b/html/deviantion.htm @@ -38,6 +38,12 @@ {{.Templates.Deviation.Post.Description}} {{end}} + {{if ne .Templates.Deviation.Related ""}} +
+ Related content + {{.Templates.Deviation.Related}} +
+ {{end}} {{if (ne .Templates.Deviation.Comments "")}} {{.Templates.Deviation.Comments}} {{end}} diff --git a/html/search.htm b/html/search.htm index 8cdcbc1..6644bfc 100644 --- a/html/search.htm +++ b/html/search.htm @@ -18,7 +18,7 @@ {{if ne .Templates.Search.List ""}} {{if ne .Templates.Search.Content.Total 0}} -

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

+

Results by request '{{.QueryRaw}}': {{.Templates.Search.Content.Total}}

{{end}} {{.Templates.Search.List}} {{else}} diff --git a/main.go b/main.go index 636c358..43b95f0 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( func main() { app.ExecuteConfig() + app.CopyTemplatesToMemory() err := devianter.UpdateCSRF() if err != nil { println(err.Error()) -- cgit v1.2.3