krz/skunky-art
Alternative privacy frontend for DeviantArt.
clone: git clone https://gitbay.org/krz/skunky-art.git
1package app
2
3import (
4 "regexp"
5 "strconv"
6 "strings"
7 "time"
8
9 "git.macaw.me/skunky/devianter"
10 "golang.org/x/net/html"
11)
12
13func (s skunkyart) GRUser() {
14 if len(s.Query) < 1 {
15 s.ReturnHTTPError(400)
16 return
17 }
18
19 var g devianter.Group
20 var daError devianter.Error
21 g.Name = s.Query
22 var err error
23 s.Templates.GroupUser.GR, err, daError = g.Get()
24 try(err)
25 if daError.RAW != nil {
26 s.Error(daError)
27 return
28 }
29
30 group := &s.Templates.GroupUser
31
32 switch s.Type {
33 case 'a':
34 g := group.GR
35 s.Atom = false
36 for _, x := range g.Gruser.Page.Modules {
37 switch x.Name {
38 case "about", "group_about":
39 switch g.Owner.Group {
40 case true:
41 var about = &x.ModuleData.GroupAbout
42 group.Group = true
43 group.CreationDate = x.ModuleData.GroupAbout.FoundatedAt.UTC().String()
44 group.About.DescriptionFormatted = ParseDescription(about.Description)
45 case false:
46 group.About.A = x.ModuleData.About
47 var about = &group.About.A
48 group.CreationDate = time.Unix(time.Now().Unix()-x.ModuleData.About.RegDate, 0).UTC().String()
49 group.About.DescriptionFormatted = ParseDescription(about.Description)
50
51 for _, val := range x.ModuleData.About.SocialLinks {
52 var social strings.Builder
53 social.WriteString(`<a target="_blank" href="`)
54 social.WriteString(val.Value)
55 social.WriteString(`">`)
56 social.WriteString(val.Value)
57 social.WriteString("</a><br>")
58 group.About.Social += social.String()
59 }
60
61 for _, val := range x.ModuleData.About.Interests {
62 var interest strings.Builder
63 interest.WriteString(val.Label)
64 interest.WriteString(": <b>")
65 interest.WriteString(val.Value)
66 interest.WriteString("</b><br>")
67 group.About.Interests += interest.String()
68 }
69 }
70 group.About.Comments = s.ParseComments(devianter.GetComments(strconv.Itoa(group.GR.Gruser.ID), "", s.Page, 4))
71
72 case "cover_deviation":
73 group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation
74 group.About.BGMeta.Url = ConvertDeviantArtUrlToSkunkyArt(group.About.BGMeta.Url)
75 group.About.BG = ParseMedia(group.About.BGMeta.Media)
76 case "group_admins":
77 var htm strings.Builder
78 for _, z := range x.ModuleData.GroupAdmins.Results {
79 htm.WriteString(BuildUserPlate(z.User.Username))
80 }
81 group.Admins += htm.String()
82 }
83
84 }
85 case 'g', 'f':
86 var all bool
87 var content devianter.Group
88
89 folderid, _ := strconv.Atoi(s.Args.Get("folder"))
90
91 if a := s.Args.Get("all"); a == "true" {
92 all = true
93 }
94
95 if s.Page == 0 {
96 s.Page++
97 }
98
99 if s.Type == 'f' {
100 content, daError = g.Favourites(s.Page, all, folderid)
101 } else {
102 content, err, daError = g.Gallery(s.Page, folderid)
103 try(err)
104 }
105
106 if daError.RAW != nil {
107 s.Error(daError)
108 return
109 }
110
111 if folderid > 0 || (s.Type == 'f' && all) {
112 group.Gallery.List = s.DeviationList(content.Content.Results, true, DeviationList{
113 More: content.Content.HasMore,
114 })
115 } else {
116 for _, x := range content.Content.Gruser.Page.Modules {
117 if l := len(x.ModuleData.Folders.Results); l != 0 {
118 var folders strings.Builder
119 folders.WriteString(`<h1 id="folders"><a href="#folder">#</a> Folders</h1><div class="folders"><br>`)
120 for _, x := range x.ModuleData.Folders.Results {
121 if x.FolderId != -1 && x.Size != 0 {
122 folders.WriteString(`<div class="block folder-item">`)
123
124 if !(x.Thumb.NSFW && !CFG.Nsfw) {
125 folders.WriteString(`<a href="`)
126 folders.WriteString(ConvertDeviantArtUrlToSkunkyArt(x.Thumb.Url))
127 folders.WriteString(`"><img loading="lazy" src="`)
128 folders.WriteString(ParseMedia(x.Thumb.Media))
129 folders.WriteString(`" title="`)
130 folders.WriteString(x.Thumb.Title)
131 folders.WriteString(`"></a>`)
132 } else {
133 folders.WriteString(`<h1>[ <span class="nsfw">NSFW</span> ]</h1>`)
134 }
135 folders.WriteString("<br>")
136
137 folders.WriteString(`<a href="group_user?folder=`)
138 folders.WriteString(strconv.Itoa(x.FolderId))
139 folders.WriteString("&q=")
140 folders.WriteString(s.Query)
141 folders.WriteString("&type=")
142 folders.WriteString(string(s.Type))
143 folders.WriteString(`">`)
144 folders.WriteString(x.Name)
145 folders.WriteString(`</a>`)
146
147 folders.WriteString("</div>")
148 }
149 }
150 folders.WriteString(`</div><h1 id="content"><a href="#content">#</a> Content</h1>`)
151 group.Gallery.Folders = folders.String()
152 }
153
154 if x.Name == "folder_deviations" {
155 group.Gallery.List = s.DeviationList(x.ModuleData.Folder.Deviations, true, DeviationList{
156 Pages: x.ModuleData.Folder.Pages,
157 More: x.ModuleData.Folder.HasMore,
158 })
159 }
160 }
161 }
162 default:
163 s.ReturnHTTPError(400)
164 }
165
166 if !s.Atom {
167 s.ExecuteTemplate("gruser.htm", "html", &s)
168 }
169}
170
171// посты
172func (s skunkyart) Deviation(author, postname string) {
173 id_search := regexp.MustCompile("[0-9]+").FindAllString(postname, -1)
174 if len(id_search) < 1 {
175 s.ReturnHTTPError(400)
176 return
177 }
178
179 var err devianter.Error
180 post := &s.Templates.Deviation
181
182 id := id_search[len(id_search)-1]
183 post.Post, err = devianter.GetDeviation(id, author)
184 if err.RAW != nil {
185 s.Error(err)
186 return
187 }
188
189 if post.Post.Comments.Total <= 50 {
190 post.Post.Comments.Cursor = ""
191 }
192
193 if post.Post.Deviation.TextContent.Excerpt != "" {
194 post.Post.Description = ParseDescription(post.Post.Deviation.TextContent)
195 } else {
196 post.Post.Description = ParseDescription(post.Post.Deviation.Extended.DescriptionText)
197 }
198
199 for _, x := range post.Post.Deviation.Extended.RelatedContent {
200 if len(x.Deviations) != 0 {
201 post.Related += s.DeviationList(x.Deviations, false)
202 }
203 }
204
205 // хештэги
206 for _, x := range post.Post.Deviation.Extended.Tags {
207 var tag strings.Builder
208 tag.WriteString(` <a href="`)
209 tag.WriteString(UrlBuilder("search", "?q=", x.Name, "&type=tag"))
210 tag.WriteString(`">#`)
211 tag.WriteString(x.Name)
212 tag.WriteString("</a>")
213
214 post.Tags += tag.String()
215 }
216
217 post.Comments = s.ParseComments(devianter.GetComments(id, post.Post.Comments.Cursor, s.Page, 1))
218 post.StringTime = post.Post.Deviation.PublishedTime.UTC().String()
219 post.Post.IMG = ParseMedia(post.Post.Deviation.Media)
220
221 s.ExecuteTemplate("deviantion.htm", "html", &s)
222}
223
224func (s skunkyart) DD() {
225 dd, err := devianter.GetDailyDeviations(s.Page)
226 if err.RAW != nil {
227 s.Error(err)
228 return
229 }
230 var strips strings.Builder
231 for _, x := range dd.Strips {
232 strips.WriteString(`<h3 class="`)
233 strips.WriteString(x.Codename)
234 strips.WriteString(`"> <a href="#`)
235 strips.WriteString(x.Codename)
236 strips.WriteString(`"># </a>`)
237 strips.WriteString(x.Title)
238 strips.WriteString(`</h3>`)
239
240 strips.WriteString(s.DeviationList(x.Deviations, false))
241 }
242 s.Templates.DDStrips = strips.String()
243 s.Templates.SomeList = s.DeviationList(dd.Deviations, true, DeviationList{
244 Pages: 0,
245 More: dd.HasMore,
246 })
247 if !s.Atom {
248 s.ExecuteTemplate("daily.htm", "html", &s)
249 }
250}
251
252func (s skunkyart) Search() {
253 if s.Query == "" {
254 s.ReturnHTTPError(400)
255 return
256 }
257
258 var err error
259 var daError devianter.Error
260 ss := &s.Templates.Search
261 switch s.Type {
262 case 'a', 't':
263 ss.Content, err, daError = devianter.PerformSearch(s.Query, s.Page, s.Type)
264 case 'g', 'f':
265 ss.Content, err, daError = devianter.PerformSearch(s.Query, s.Page, s.Type, s.Args.Get("usr"))
266 case 'r': // скраппер, поскольку девиантартовцы зажопили гостевое API для поиска групп
267 var (
268 usernames = make(map[int]string)
269 url strings.Builder
270 num int
271 )
272
273 s.Page++
274
275 url.WriteString("https://www.deviantart.com/groups/?q=")
276 url.WriteString(s.Query)
277 if s.Page > 1 {
278 url.WriteString("&offset=")
279 url.WriteString(strconv.Itoa(10 * s.Page))
280 }
281
282 dwnld := Download(url.String())
283
284 for z := html.NewTokenizer(strings.NewReader(string(dwnld.Body))); ; {
285 if n, token := z.Next(), z.Token(); n == html.StartTagToken && token.Data == "a" {
286 for _, x := range token.Attr {
287 if x.Key == "class" && x.Val == "u regular username" {
288 usernames[num] = GetValueOfTag(z)
289 num++
290 }
291 }
292 } else if n == 0 {
293 break
294 } else {
295 continue
296 }
297 }
298
299 if l := len(usernames); l != 0 {
300 ss.List += `<div class="content plates">`
301 for x := 0; x < len(usernames); x++ {
302 ss.List += BuildUserPlate(usernames[x])
303 }
304 ss.List += `</div>`
305 ss.List += s.NavBase(DeviationList{
306 More: true,
307 })
308 }
309 default:
310 s.ReturnHTTPError(400)
311 return
312 }
313 try(err)
314
315 if s.Type != 'r' {
316 if daError.RAW != nil {
317 s.Error(daError)
318 return
319 }
320
321 ss.List = s.DeviationList(ss.Content.Results, false, DeviationList{
322 Pages: ss.Content.Pages,
323 More: ss.Content.HasMore,
324 })
325 }
326
327 s.ExecuteTemplate("search.htm", "html", &s)
328}
329
330func (s skunkyart) Emojitar(name string) {
331 if name == "" || !(s.Type == 'a' || s.Type == 'e') {
332 s.ReturnHTTPError(400)
333 return
334 }
335
336 ae, e := devianter.AEmedia(name, s.Type)
337 if e != nil {
338 s.ReturnHTTPError(404)
339 }
340 wr(s.Writer, ae)
341}