2024-06-13 20:56:03 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2024-07-13 18:32:04 +00:00
|
|
|
"encoding/json"
|
2024-06-13 20:56:03 +00:00
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
2024-06-27 11:51:46 +00:00
|
|
|
"time"
|
2024-06-13 20:56:03 +00:00
|
|
|
|
|
|
|
"git.macaw.me/skunky/devianter"
|
2024-07-09 09:54:15 +00:00
|
|
|
"golang.org/x/net/html"
|
2024-06-13 20:56:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var wr = io.WriteString
|
|
|
|
|
|
|
|
type skunkyart struct {
|
2024-07-13 18:32:04 +00:00
|
|
|
Writer http.ResponseWriter
|
|
|
|
|
2024-08-13 12:59:52 +00:00
|
|
|
Args url.Values
|
|
|
|
Page int
|
|
|
|
Type rune
|
|
|
|
Atom bool
|
|
|
|
|
|
|
|
BasePath, Endpoint string
|
|
|
|
Query, QueryRaw string
|
2024-07-13 18:32:04 +00:00
|
|
|
|
|
|
|
Templates struct {
|
2024-07-05 21:46:25 +00:00
|
|
|
About struct {
|
2024-07-13 18:32:04 +00:00
|
|
|
Proxy bool
|
|
|
|
Nsfw bool
|
2024-08-01 19:48:05 +00:00
|
|
|
Instances []settings
|
2024-07-05 21:46:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SomeList string
|
2024-07-29 22:06:40 +00:00
|
|
|
DDStrips string
|
2024-07-05 21:46:25 +00:00
|
|
|
Deviation struct {
|
|
|
|
Post devianter.Post
|
2024-07-06 17:06:04 +00:00
|
|
|
Related string
|
2024-07-05 21:46:25 +00:00
|
|
|
StringTime string
|
|
|
|
Tags string
|
|
|
|
Comments string
|
|
|
|
}
|
|
|
|
|
2024-06-30 11:40:27 +00:00
|
|
|
GroupUser struct {
|
|
|
|
GR devianter.GRuser
|
2024-07-04 08:26:52 +00:00
|
|
|
Admins string
|
|
|
|
Group bool
|
2024-06-30 11:40:27 +00:00
|
|
|
CreationDate string
|
|
|
|
|
|
|
|
About struct {
|
|
|
|
A devianter.About
|
|
|
|
|
|
|
|
DescriptionFormatted string
|
|
|
|
Interests, Social string
|
|
|
|
Comments string
|
|
|
|
BG string
|
|
|
|
BGMeta devianter.Deviation
|
2024-06-14 17:04:23 +00:00
|
|
|
}
|
|
|
|
|
2024-06-30 11:40:27 +00:00
|
|
|
Gallery struct {
|
2024-07-04 08:26:52 +00:00
|
|
|
Folders string
|
|
|
|
Pages int
|
|
|
|
List string
|
2024-06-14 17:04:23 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-30 11:40:27 +00:00
|
|
|
Search struct {
|
|
|
|
Content devianter.Search
|
|
|
|
List string
|
|
|
|
}
|
2024-06-14 17:04:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-27 11:51:46 +00:00
|
|
|
func (s skunkyart) GRUser() {
|
|
|
|
if len(s.Query) < 1 {
|
2024-06-30 11:40:27 +00:00
|
|
|
s.ReturnHTTPError(400)
|
2024-06-27 11:51:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var g devianter.Group
|
|
|
|
g.Name = s.Query
|
2024-07-29 22:06:40 +00:00
|
|
|
var err error
|
|
|
|
s.Templates.GroupUser.GR, err = g.GetGroup()
|
|
|
|
try(err)
|
|
|
|
|
2024-06-30 11:40:27 +00:00
|
|
|
group := &s.Templates.GroupUser
|
2024-06-27 11:51:46 +00:00
|
|
|
|
2024-06-30 11:40:27 +00:00
|
|
|
switch s.Type {
|
|
|
|
case 'a':
|
2024-07-04 08:26:52 +00:00
|
|
|
g := group.GR
|
2024-07-05 21:46:25 +00:00
|
|
|
s.Atom = false
|
2024-07-04 08:26:52 +00:00
|
|
|
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:
|
2024-06-30 11:40:27 +00:00
|
|
|
group.About.A = x.ModuleData.About
|
2024-07-04 08:26:52 +00:00
|
|
|
var about = &group.About.A
|
|
|
|
group.CreationDate = time.Unix(time.Now().Unix()-x.ModuleData.About.RegDate, 0).UTC().String()
|
|
|
|
|
2024-06-30 11:40:27 +00:00
|
|
|
group.About.DescriptionFormatted = ParseDescription(about.Description)
|
|
|
|
|
|
|
|
for _, val := range x.ModuleData.About.SocialLinks {
|
|
|
|
var social strings.Builder
|
|
|
|
social.WriteString(`<a target="_blank" href="`)
|
|
|
|
social.WriteString(val.Value)
|
|
|
|
social.WriteString(`">`)
|
|
|
|
social.WriteString(val.Value)
|
|
|
|
social.WriteString("</a><br>")
|
|
|
|
group.About.Social += social.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, val := range x.ModuleData.About.Interests {
|
|
|
|
var interest strings.Builder
|
|
|
|
interest.WriteString(val.Label)
|
|
|
|
interest.WriteString(": <b>")
|
|
|
|
interest.WriteString(val.Value)
|
|
|
|
interest.WriteString("</b><br>")
|
|
|
|
group.About.Interests += interest.String()
|
|
|
|
}
|
2024-07-04 08:26:52 +00:00
|
|
|
}
|
2024-07-29 22:06:40 +00:00
|
|
|
group.About.Comments = s.ParseComments(devianter.GetComments(
|
2024-07-04 08:26:52 +00:00
|
|
|
strconv.Itoa(group.GR.Gruser.ID),
|
|
|
|
"",
|
|
|
|
s.Page,
|
|
|
|
4,
|
|
|
|
))
|
2024-06-30 11:40:27 +00:00
|
|
|
|
2024-07-04 08:26:52 +00:00
|
|
|
case "cover_deviation":
|
|
|
|
group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation
|
2024-07-13 18:32:04 +00:00
|
|
|
group.About.BGMeta.Url = ConvertDeviantArtUrlToSkunkyArt(group.About.BGMeta.Url)
|
2024-08-13 12:59:52 +00:00
|
|
|
group.About.BG = ParseMedia(group.About.BGMeta.Media, group.About.BGMeta.Title)
|
2024-07-04 08:26:52 +00:00
|
|
|
case "group_admins":
|
|
|
|
var htm strings.Builder
|
|
|
|
for _, z := range x.ModuleData.GroupAdmins.Results {
|
2024-07-09 09:54:15 +00:00
|
|
|
htm.WriteString(BuildUserPlate(z.User.Username))
|
2024-06-30 11:40:27 +00:00
|
|
|
}
|
2024-07-04 08:26:52 +00:00
|
|
|
group.Admins += htm.String()
|
2024-06-27 11:51:46 +00:00
|
|
|
}
|
2024-06-13 20:56:03 +00:00
|
|
|
|
|
|
|
}
|
2024-06-30 11:40:27 +00:00
|
|
|
case 'g':
|
2024-07-04 08:26:52 +00:00
|
|
|
folderid, _ := strconv.Atoi(s.Args.Get("folder"))
|
|
|
|
if s.Page == 0 {
|
|
|
|
s.Page++
|
|
|
|
}
|
|
|
|
|
2024-07-29 22:06:40 +00:00
|
|
|
gallery, err := g.GetGallery(s.Page, folderid)
|
|
|
|
try(err)
|
|
|
|
|
2024-07-04 08:26:52 +00:00
|
|
|
if folderid > 0 {
|
2024-07-29 22:06:40 +00:00
|
|
|
group.Gallery.List = s.DeviationList(gallery.Content.Results, true, DeviationList{
|
2024-07-04 08:26:52 +00:00
|
|
|
More: gallery.Content.HasMore,
|
2024-06-30 11:40:27 +00:00
|
|
|
})
|
2024-07-04 08:26:52 +00:00
|
|
|
} else {
|
|
|
|
for _, x := range gallery.Content.Gruser.Page.Modules {
|
|
|
|
if l := len(x.ModuleData.Folders.Results); l != 0 {
|
|
|
|
var folders strings.Builder
|
2024-07-08 09:47:28 +00:00
|
|
|
folders.WriteString(`<h1 id="folders"><a href="#folder">#</a> Folders</h1><div class="folders"><br>`)
|
|
|
|
for _, x := range x.ModuleData.Folders.Results {
|
|
|
|
folders.WriteString(`<div class="block folder-item">`)
|
|
|
|
|
2024-07-13 18:32:04 +00:00
|
|
|
if !(x.Thumb.NSFW && !CFG.Nsfw) {
|
|
|
|
folders.WriteString(`<a href="`)
|
|
|
|
folders.WriteString(ConvertDeviantArtUrlToSkunkyArt(x.Thumb.Url))
|
|
|
|
folders.WriteString(`"><img loading="lazy" src="`)
|
2024-08-13 12:59:52 +00:00
|
|
|
folders.WriteString(ParseMedia(x.Thumb.Media, x.Thumb.Title))
|
2024-07-13 18:32:04 +00:00
|
|
|
folders.WriteString(`" title="`)
|
|
|
|
folders.WriteString(x.Thumb.Title)
|
|
|
|
folders.WriteString(`"></a>`)
|
|
|
|
} else {
|
|
|
|
folders.WriteString(`<h1>[ <span class="nsfw">NSFW</span> ]</h1>`)
|
|
|
|
}
|
|
|
|
folders.WriteString("<br>")
|
2024-07-08 09:47:28 +00:00
|
|
|
|
2024-08-13 12:59:52 +00:00
|
|
|
folders.WriteString(`<a href="group_user?folder=`)
|
2024-07-04 08:26:52 +00:00
|
|
|
folders.WriteString(strconv.Itoa(x.FolderId))
|
|
|
|
folders.WriteString("&q=")
|
|
|
|
folders.WriteString(s.Query)
|
|
|
|
folders.WriteString("&type=")
|
|
|
|
folders.WriteString(string(s.Type))
|
|
|
|
folders.WriteString(`">`)
|
|
|
|
folders.WriteString(x.Name)
|
|
|
|
folders.WriteString(`</a>`)
|
2024-07-08 09:47:28 +00:00
|
|
|
|
|
|
|
folders.WriteString("</div>")
|
2024-07-04 08:26:52 +00:00
|
|
|
}
|
2024-07-08 09:47:28 +00:00
|
|
|
folders.WriteString(`</div><h1 id="content"><a href="#content">#</a> Content</h1>`)
|
2024-07-04 08:26:52 +00:00
|
|
|
group.Gallery.Folders = folders.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
if x.Name == "folder_deviations" {
|
2024-07-29 22:06:40 +00:00
|
|
|
group.Gallery.List = s.DeviationList(x.ModuleData.Folder.Deviations, true, DeviationList{
|
2024-07-04 08:26:52 +00:00
|
|
|
Pages: x.ModuleData.Folder.Pages,
|
|
|
|
More: x.ModuleData.Folder.HasMore,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
2024-06-30 11:40:27 +00:00
|
|
|
default:
|
|
|
|
s.ReturnHTTPError(400)
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
2024-06-14 17:04:23 +00:00
|
|
|
|
2024-07-05 21:46:25 +00:00
|
|
|
if !s.Atom {
|
2024-08-13 12:59:52 +00:00
|
|
|
s.ExecuteTemplate("gruser.htm", "html", &s)
|
2024-07-05 08:08:32 +00:00
|
|
|
}
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// посты
|
|
|
|
func (s skunkyart) Deviation(author, postname string) {
|
2024-07-05 21:46:25 +00:00
|
|
|
id_search := regexp.MustCompile("[0-9]+").FindAllString(postname, -1)
|
2024-08-01 19:48:05 +00:00
|
|
|
if len(id_search) < 1 {
|
|
|
|
s.ReturnHTTPError(400)
|
|
|
|
return
|
|
|
|
}
|
2024-06-13 20:56:03 +00:00
|
|
|
|
2024-08-01 19:48:05 +00:00
|
|
|
post := &s.Templates.Deviation
|
2024-06-13 20:56:03 +00:00
|
|
|
|
2024-08-01 19:48:05 +00:00
|
|
|
id := id_search[len(id_search)-1]
|
|
|
|
post.Post = devianter.GetDeviation(id, author)
|
2024-06-13 20:56:03 +00:00
|
|
|
|
2024-08-01 19:48:05 +00:00
|
|
|
if post.Post.Deviation.TextContent.Excerpt != "" {
|
|
|
|
post.Post.Description = ParseDescription(post.Post.Deviation.TextContent)
|
|
|
|
} else {
|
|
|
|
post.Post.Description = ParseDescription(post.Post.Deviation.Extended.DescriptionText)
|
|
|
|
}
|
|
|
|
// время публикации
|
|
|
|
post.StringTime = post.Post.Deviation.PublishedTime.UTC().String()
|
2024-08-13 12:59:52 +00:00
|
|
|
post.Post.IMG = ParseMedia(post.Post.Deviation.Media, post.Post.Deviation.Title)
|
2024-08-01 19:48:05 +00:00
|
|
|
for _, x := range post.Post.Deviation.Extended.RelatedContent {
|
|
|
|
if len(x.Deviations) != 0 {
|
|
|
|
post.Related += s.DeviationList(x.Deviations, false)
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
2024-08-01 19:48:05 +00:00
|
|
|
}
|
2024-06-13 20:56:03 +00:00
|
|
|
|
2024-08-01 19:48:05 +00:00
|
|
|
// хештэги
|
|
|
|
for _, x := range post.Post.Deviation.Extended.Tags {
|
|
|
|
var tag strings.Builder
|
|
|
|
tag.WriteString(` <a href="`)
|
|
|
|
tag.WriteString(UrlBuilder("search", "?q=", x.Name, "&type=tag"))
|
|
|
|
tag.WriteString(`">#`)
|
|
|
|
tag.WriteString(x.Name)
|
|
|
|
tag.WriteString("</a>")
|
2024-07-08 09:47:28 +00:00
|
|
|
|
2024-08-01 19:48:05 +00:00
|
|
|
post.Tags += tag.String()
|
|
|
|
}
|
2024-06-27 11:51:46 +00:00
|
|
|
|
2024-08-01 19:48:05 +00:00
|
|
|
if post.Post.Comments.Total <= 50 {
|
|
|
|
post.Post.Comments.Cursor = ""
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
2024-08-01 19:48:05 +00:00
|
|
|
|
|
|
|
post.Comments = s.ParseComments(devianter.GetComments(id, post.Post.Comments.Cursor, s.Page, 1))
|
|
|
|
|
2024-08-13 12:59:52 +00:00
|
|
|
s.ExecuteTemplate("deviantion.htm", "html", &s)
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2024-06-14 17:04:23 +00:00
|
|
|
func (s skunkyart) DD() {
|
2024-07-29 22:06:40 +00:00
|
|
|
dd := devianter.GetDailyDeviations(s.Page)
|
|
|
|
var strips strings.Builder
|
|
|
|
for _, x := range dd.Strips {
|
|
|
|
strips.WriteString(`<h3 class="`)
|
|
|
|
strips.WriteString(x.Codename)
|
|
|
|
strips.WriteString(`"> <a href="#`)
|
|
|
|
strips.WriteString(x.Codename)
|
|
|
|
strips.WriteString(`"># </a>`)
|
|
|
|
strips.WriteString(x.Title)
|
|
|
|
strips.WriteString(`</h3>`)
|
|
|
|
|
|
|
|
strips.WriteString(s.DeviationList(x.Deviations, false))
|
|
|
|
}
|
|
|
|
s.Templates.DDStrips = strips.String()
|
|
|
|
s.Templates.SomeList = s.DeviationList(dd.Deviations, true, DeviationList{
|
2024-06-14 17:04:23 +00:00
|
|
|
Pages: 0,
|
|
|
|
More: dd.HasMore,
|
2024-07-05 08:08:32 +00:00
|
|
|
})
|
2024-07-05 21:46:25 +00:00
|
|
|
if !s.Atom {
|
2024-08-13 12:59:52 +00:00
|
|
|
s.ExecuteTemplate("daily.htm", "html", &s)
|
2024-07-05 08:08:32 +00:00
|
|
|
}
|
2024-06-14 17:04:23 +00:00
|
|
|
}
|
|
|
|
|
2024-06-13 20:56:03 +00:00
|
|
|
func (s skunkyart) Search() {
|
2024-08-13 12:59:52 +00:00
|
|
|
if s.Query == "" {
|
|
|
|
s.ReturnHTTPError(400)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-07-29 22:06:40 +00:00
|
|
|
var err error
|
2024-06-30 11:40:27 +00:00
|
|
|
ss := &s.Templates.Search
|
2024-06-27 11:51:46 +00:00
|
|
|
switch s.Type {
|
2024-06-30 11:40:27 +00:00
|
|
|
case 'a', 't':
|
2024-07-29 22:06:40 +00:00
|
|
|
ss.Content, err = devianter.PerformSearch(s.Query, s.Page, s.Type)
|
2024-06-30 11:40:27 +00:00
|
|
|
case 'g':
|
2024-07-29 22:06:40 +00:00
|
|
|
ss.Content, err = devianter.PerformSearch(s.Query, s.Page, s.Type, s.Args.Get("usr"))
|
2024-07-09 09:54:15 +00:00
|
|
|
case 'r': // скраппер, поскольку девиантартовцы зажопили гостевое API для поиска групп
|
|
|
|
var (
|
|
|
|
usernames = make(map[int]string)
|
|
|
|
url strings.Builder
|
|
|
|
num int
|
|
|
|
)
|
|
|
|
|
|
|
|
s.Page++
|
|
|
|
|
|
|
|
url.WriteString("https://www.deviantart.com/groups/?q=")
|
|
|
|
url.WriteString(s.Query)
|
|
|
|
if s.Page > 1 {
|
|
|
|
url.WriteString("&offset=")
|
|
|
|
url.WriteString(strconv.Itoa(10 * s.Page))
|
|
|
|
}
|
|
|
|
|
2024-07-13 18:32:04 +00:00
|
|
|
dwnld := Download(url.String())
|
2024-07-09 09:54:15 +00:00
|
|
|
|
2024-07-13 18:32:04 +00:00
|
|
|
for z := html.NewTokenizer(strings.NewReader(string(dwnld.Body))); ; {
|
2024-07-09 09:54:15 +00:00
|
|
|
if n, token := z.Next(), z.Token(); n == html.StartTagToken && token.Data == "a" {
|
|
|
|
for _, x := range token.Attr {
|
|
|
|
if x.Key == "class" && x.Val == "u regular username" {
|
2024-07-13 18:32:04 +00:00
|
|
|
usernames[num] = GetValueOfTag(z)
|
2024-07-09 09:54:15 +00:00
|
|
|
num++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if n == 0 {
|
|
|
|
break
|
|
|
|
} else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if l := len(usernames); l != 0 {
|
|
|
|
ss.List += `<div class="content plates">`
|
|
|
|
for x := 0; x < len(usernames); x++ {
|
|
|
|
ss.List += BuildUserPlate(usernames[x])
|
|
|
|
}
|
|
|
|
ss.List += `</div>`
|
2024-07-13 18:32:04 +00:00
|
|
|
ss.List += s.NavBase(DeviationList{
|
|
|
|
More: true,
|
|
|
|
})
|
2024-07-09 09:54:15 +00:00
|
|
|
}
|
2024-06-27 11:51:46 +00:00
|
|
|
default:
|
2024-06-30 11:40:27 +00:00
|
|
|
s.ReturnHTTPError(400)
|
2024-08-13 12:59:52 +00:00
|
|
|
return
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
2024-07-29 22:06:40 +00:00
|
|
|
try(err)
|
2024-06-30 11:40:27 +00:00
|
|
|
|
2024-07-09 09:54:15 +00:00
|
|
|
if s.Type != 'r' {
|
2024-07-29 22:06:40 +00:00
|
|
|
ss.List = s.DeviationList(ss.Content.Results, false, DeviationList{
|
2024-07-09 09:54:15 +00:00
|
|
|
Pages: ss.Content.Pages,
|
|
|
|
More: ss.Content.HasMore,
|
|
|
|
})
|
|
|
|
}
|
2024-06-30 11:40:27 +00:00
|
|
|
|
2024-08-13 12:59:52 +00:00
|
|
|
s.ExecuteTemplate("search.htm", "html", &s)
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s skunkyart) Emojitar(name string) {
|
2024-08-01 19:48:05 +00:00
|
|
|
if name == "" || !(s.Type == 'a' || s.Type == 'e') {
|
2024-06-30 11:40:27 +00:00
|
|
|
s.ReturnHTTPError(400)
|
2024-08-01 19:48:05 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ae, e := devianter.AEmedia(name, s.Type)
|
|
|
|
if e != nil {
|
|
|
|
s.ReturnHTTPError(404)
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
2024-08-01 19:48:05 +00:00
|
|
|
wr(s.Writer, ae)
|
2024-06-13 20:56:03 +00:00
|
|
|
}
|
2024-07-05 21:46:25 +00:00
|
|
|
|
|
|
|
func (s skunkyart) About() {
|
|
|
|
s.Templates.About.Nsfw = CFG.Nsfw
|
|
|
|
s.Templates.About.Proxy = CFG.Proxy
|
2024-08-13 12:59:52 +00:00
|
|
|
try(json.Unmarshal(instances, &s.Templates.About))
|
|
|
|
s.ExecuteTemplate("about.htm", "html", &s)
|
2024-07-05 21:46:25 +00:00
|
|
|
}
|