Commit 0f528ee9fa

0f528ee9fa8b84c5e7532e22480b8b4b3ff7d5ba

parent: e07e1a25b2

Unsigned

lost+skunk <skunky@ebloid.ru> · 2024-07-09 09:54 UTC

Поиск по группам

Layout: unified · split

app/util.go +25 −15
@@ -66,12 +66,35 @@ func (s skunkyart) ConvertDeviantArtUrlToSkunkyArt(url string) (output string) {
66 return 66 return
67} 67}
68 68
69func BuildUserPlate(name string) string {
70 var htm strings.Builder
71 htm.WriteString(`<div class="user-plate"><img src="`)
72 htm.WriteString(UrlBuilder("media", "emojitar", name, "?type=a"))
73 htm.WriteString(`"><a href="`)
74 htm.WriteString(UrlBuilder("group_user", "?type=about&q=", name))
75 htm.WriteString(`">`)
76 htm.WriteString(name)
77 htm.WriteString(`</a></div>`)
78 return htm.String()
79}
80
69type text struct { 81type text struct {
70 TXT string 82 TXT string
71 from int 83 from int
72 to int 84 to int
73} 85}
74 86
87func tagval(t *html.Tokenizer) string {
88 for tt := t.Next(); ; {
89 switch tt {
90 default:
91 return ""
92 case html.TextToken:
93 return string(t.Text())
94 }
95 }
96}
97
75func ParseDescription(dscr devianter.Text) string { 98func ParseDescription(dscr devianter.Text) string {
76 var parseddescription strings.Builder 99 var parseddescription strings.Builder
77 TagBuilder := func(tag string, content string) string { 100 TagBuilder := func(tag string, content string) string {
@@ -182,20 +205,7 @@ func ParseDescription(dscr devianter.Text) string {
182 } 205 }
183 } 206 }
184 } else if dl != 0 { 207 } else if dl != 0 {
185 tagval := func(t *html.Tokenizer) string { 208 for tt := html.NewTokenizer(strings.NewReader(dscr.Html.Markup)); ; {
186 for {
187 tt := t.Next()
188 switch tt {
189 case html.ErrorToken:
190 return ""
191 case html.TextToken:
192 return string(t.Text())
193 }
194 }
195 }
196
197 tt := html.NewTokenizer(strings.NewReader(dscr.Html.Markup))
198 for {
199 t := tt.Next() 209 t := tt.Next()
200 switch t { 210 switch t {
201 case html.ErrorToken: 211 case html.ErrorToken:
@@ -314,7 +324,7 @@ func (s skunkyart) NavBase(c dlist) string {
314 } 324 }
315 325
316 // вперёд-назад 326 // вперёд-назад
317 if c.More { 327 if p != 417 || c.More {
318 prevrev("| Next =>", p+1, false) 328 prevrev("| Next =>", p+1, false)
319 } 329 }
320 330
app/wrapper.go +53 −11
@@ -10,6 +10,7 @@ import (
10 "time" 10 "time"
11 11
12 "git.macaw.me/skunky/devianter" 12 "git.macaw.me/skunky/devianter"
13 "golang.org/x/net/html"
13) 14)
14 15
15var wr = io.WriteString 16var wr = io.WriteString
@@ -131,13 +132,7 @@ func (s skunkyart) GRUser() {
131 case "group_admins": 132 case "group_admins":
132 var htm strings.Builder 133 var htm strings.Builder
133 for _, z := range x.ModuleData.GroupAdmins.Results { 134 for _, z := range x.ModuleData.GroupAdmins.Results {
134 htm.WriteString(`<div class="admin"><img src="`) 135 htm.WriteString(BuildUserPlate(z.User.Username))
135 htm.WriteString(UrlBuilder("media", "emojitar", z.User.Username, "?type=a"))
136 htm.WriteString(`"><a href="`)
137 htm.WriteString(UrlBuilder("group_user", "?type=about&q=", z.User.Username))
138 htm.WriteString(`">`)
139 htm.WriteString(z.User.Username)
140 htm.WriteString(`</a></div>`)
141 } 136 }
142 group.Admins += htm.String() 137 group.Admins += htm.String()
143 } 138 }
@@ -270,15 +265,62 @@ func (s skunkyart) Search() {
270 ss.Content, e = devianter.SearchFunc(s.Query, s.Page, s.Type) 265 ss.Content, e = devianter.SearchFunc(s.Query, s.Page, s.Type)
271 case 'g': 266 case 'g':
272 ss.Content, e = devianter.SearchFunc(s.Query, s.Page, s.Type, s.Args.Get("usr")) 267 ss.Content, e = devianter.SearchFunc(s.Query, s.Page, s.Type, s.Args.Get("usr"))
268 case 'r': // скраппер, поскольку девиантартовцы зажопили гостевое API для поиска групп
269 var (
270 usernames = make(map[int]string)
271 url strings.Builder
272 num int
273 )
274
275 s.Page++
276
277 url.WriteString("https://www.deviantart.com/groups/?q=")
278 url.WriteString(s.Query)
279 if s.Page > 1 {
280 url.WriteString("&offset=")
281 url.WriteString(strconv.Itoa(10 * s.Page))
282 }
283
284 r, err := http.Get(url.String())
285 if err != nil {
286 s.ReturnHTTPError(502)
287 }
288 defer r.Body.Close()
289
290 for z := html.NewTokenizer(r.Body); ; {
291 if n, token := z.Next(), z.Token(); n == html.StartTagToken && token.Data == "a" {
292 for _, x := range token.Attr {
293 if x.Key == "class" && x.Val == "u regular username" {
294 usernames[num] = tagval(z)
295 num++
296 }
297 }
298 } else if n == 0 {
299 break
300 } else {
301 continue
302 }
303 }
304
305 if l := len(usernames); l != 0 {
306 ss.List += `<div class="content plates">`
307 for x := 0; x < len(usernames); x++ {
308 ss.List += BuildUserPlate(usernames[x])
309 }
310 ss.List += `</div>`
311 ss.List += s.NavBase(dlist{})
312 }
273 default: 313 default:
274 s.ReturnHTTPError(400) 314 s.ReturnHTTPError(400)
275 } 315 }
276 err(e) 316 err(e)
277 317
278 ss.List = s.DeviationList(ss.Content.Results, dlist{ 318 if s.Type != 'r' {
279 Pages: ss.Content.Pages, 319 ss.List = s.DeviationList(ss.Content.Results, dlist{
280 More: ss.Content.HasMore, 320 Pages: ss.Content.Pages,
281 }) 321 More: ss.Content.HasMore,
322 })
323 }
282 324
283 s.ExecuteTemplate("html/search.htm", &s) 325 s.ExecuteTemplate("html/search.htm", &s)
284} 326}
css/skunky.css +9 −5
@@ -82,7 +82,7 @@ form input, button, select {
82 border: 3px solid #4d27d6; 82 border: 3px solid #4d27d6;
83 transition: 400ms; 83 transition: 400ms;
84} 84}
85.block img, .admins .admin img{ 85.block img, .plates .user-plate img{
86 width: 100%; 86 width: 100%;
87} 87}
88.block p { 88.block p {
@@ -103,16 +103,20 @@ form input, button, select {
103 background-color: #060820; 103 background-color: #060820;
104 border: 3px solid #060820; 104 border: 3px solid #060820;
105} 105}
106.admins { 106.plates {
107 display: flex 107 display: flex
108} 108}
109.admins .admin { 109.admins .user-plate {
110 margin-left: 1%; 110 width: 5%;
111 background-color: #011522; 111 background-color: #011522;
112}
113.plates .user-plate {
114 margin-left: 1%;
115 background-color: #091f19;
112 padding: 3px; 116 padding: 3px;
113 word-break: break-all; 117 word-break: break-all;
114 text-align: center; 118 text-align: center;
115 width: 5%; 119 max-width: 15%;
116} 120}
117 121
118@media screen and (orientation: portrait) { 122@media screen and (orientation: portrait) {
html/about.htm +1
@@ -12,6 +12,7 @@
12 <select name="type"> 12 <select name="type">
13 <option value="all">All</option> 13 <option value="all">All</option>
14 <option value="tag">Tag</option> 14 <option value="tag">Tag</option>
15 <option value="r">Groups</option>
15 </select> 16 </select>
16 <button type="submit">Search!</button> 17 <button type="submit">Search!</button>
17 </form> 18 </form>
html/deviantion.htm +1
@@ -12,6 +12,7 @@
12 <select name="type"> 12 <select name="type">
13 <option value="all">All</option> 13 <option value="all">All</option>
14 <option value="tag">Tag</option> 14 <option value="tag">Tag</option>
15 <option value="r">Groups</option>
15 </select> 16 </select>
16 <button type="submit">Search!</button> 17 <button type="submit">Search!</button>
17 </form> 18 </form>
html/gruser.htm +2 −1
@@ -22,6 +22,7 @@
22 <option value="gallery">Gallery</option> 22 <option value="gallery">Gallery</option>
23 <option value="all">All</option> 23 <option value="all">All</option>
24 <option value="tag">Tag</option> 24 <option value="tag">Tag</option>
25 <option value="r">Groups</option>
25 </select> 26 </select>
26 <button type="submit">Search!</button> 27 <button type="submit">Search!</button>
27 </form> <h1>| {{.Templates.GroupUser.GR.Owner.Username}}</h1> 28 </form> <h1>| {{.Templates.GroupUser.GR.Owner.Username}}</h1>
@@ -57,7 +58,7 @@
57 58
58 {{if ne .Templates.GroupUser.Admins ""}} 59 {{if ne .Templates.GroupUser.Admins ""}}
59 <h3 id="admins"><a href="#admins">#</a> Group admins</h3> 60 <h3 id="admins"><a href="#admins">#</a> Group admins</h3>
60 <div class="admins"> 61 <div class="plates admins">
61 {{.Templates.GroupUser.Admins}} 62 {{.Templates.GroupUser.Admins}}
62 </div> 63 </div>
63 {{end}} 64 {{end}}
html/index.htm +1
@@ -11,6 +11,7 @@
11 <select name="type"> 11 <select name="type">
12 <option value="all">All</option> 12 <option value="all">All</option>
13 <option value="tag">Tag</option> 13 <option value="tag">Tag</option>
14 <option value="r">Groups</option>
14 </select> 15 </select>
15 <button type="submit">Search!</button> 16 <button type="submit">Search!</button>
16 </form> 17 </form>
html/list.htm +1
@@ -12,6 +12,7 @@
12 <select name="type"> 12 <select name="type">
13 <option value="all">All</option> 13 <option value="all">All</option>
14 <option value="tag">Tag</option> 14 <option value="tag">Tag</option>
15 <option value="r">Groups</option>
15 </select> 16 </select>
16 <button type="submit">Search!</button> 17 <button type="submit">Search!</button>
17 </form> 18 </form>
html/search.htm +1
@@ -12,6 +12,7 @@
12 <select name="type"> 12 <select name="type">
13 <option value="all">All</option> 13 <option value="all">All</option>
14 <option value="tag">Tag</option> 14 <option value="tag">Tag</option>
15 <option value="r">Groups</option>
15 </select> 16 </select>
16 <button type="submit">Search!</button> 17 <button type="submit">Search!</button>
17 </form> 18 </form>