Commit e07e1a25b2

e07e1a25b26d3fd2b8fd097491d055fe7b002d2b

parent: 99fe9cf964

Unsigned

lost+skunk <skunky@ebloid.ru> · 2024-07-08 16:01 UTC

небольшие улучшения парсинга описания/комментариев

Layout: unified · split

app/util.go +106 −6
@@ -14,6 +14,7 @@ import (
14 "time" 14 "time"
15 15
16 "git.macaw.me/skunky/devianter" 16 "git.macaw.me/skunky/devianter"
17 "golang.org/x/net/html"
17) 18)
18 19
19// парсинг темплейтов 20// парсинг темплейтов
@@ -95,18 +96,59 @@ func ParseDescription(dscr devianter.Text) string {
95 description[dl-1] == '}' { 96 description[dl-1] == '}' {
96 var descr struct { 97 var descr struct {
97 Blocks []struct { 98 Blocks []struct {
98 Key, Text, Type string 99 Text, Type string
99 InlineStyleRanges []struct { 100 InlineStyleRanges []struct {
100 Offset, Length int 101 Offset, Length int
101 Style string 102 Style string
102 } 103 }
104 EntityRanges []struct {
105 Offset, Length int
106 Key int
107 }
108 Data struct {
109 TextAlignment string
110 }
111 }
112 EntityMap map[string]struct {
113 Type string
114 Data struct {
115 Config struct {
116 Aligment string
117 Width int
118 }
119 Data devianter.Deviation
120 }
103 } 121 }
104 } 122 }
105 e := json.Unmarshal([]byte(description), &descr) 123 e := json.Unmarshal([]byte(description), &descr)
106 err(e) 124 err(e)
107 125
126 entities := make(map[int]devianter.Deviation)
127 for n, x := range descr.EntityMap {
128 num, _ := strconv.Atoi(n)
129 entities[num] = x.Data.Data
130 }
131
108 for _, x := range descr.Blocks { 132 for _, x := range descr.Blocks {
109 ranges := make(map[int]text) 133 ranges := make(map[int]text)
134
135 if len(x.InlineStyleRanges) == 0 {
136 switch x.Type {
137 case "atomic":
138 d := entities[x.EntityRanges[0].Key]
139 parseddescription.WriteString(`<img width="50%" src="`)
140 parseddescription.WriteString(ParseMedia(d.Media))
141 parseddescription.WriteString(`" title="`)
142 parseddescription.WriteString(d.Author.Username)
143 parseddescription.WriteString(" - ")
144 parseddescription.WriteString(d.Title)
145 parseddescription.WriteString(`">`)
146 case "unstyled":
147 parseddescription.WriteString(x.Text)
148 }
149 parseddescription.WriteString("<br>")
150 }
151
110 for i, rngs := range x.InlineStyleRanges { 152 for i, rngs := range x.InlineStyleRanges {
111 var tag string 153 var tag string
112 154
@@ -140,7 +182,66 @@ func ParseDescription(dscr devianter.Text) string {
140 } 182 }
141 } 183 }
142 } else if dl != 0 { 184 } else if dl != 0 {
143 parseddescription.WriteString(description) 185 tagval := func(t *html.Tokenizer) string {
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()
200 switch t {
201 case html.ErrorToken:
202 return parseddescription.String()
203 case html.StartTagToken, html.EndTagToken, html.SelfClosingTagToken:
204 token := tt.Token()
205 switch token.Data {
206 case "a":
207 for _, a := range token.Attr {
208 if a.Key == "href" {
209 url := strings.ReplaceAll(a.Val, "https://www.deviantart.com/users/outgoing?", "")
210 if strings.Contains(url, "deviantart") {
211 url = strings.ReplaceAll(url, "https://www.deviantart.com/", "")
212 url = strings.ReplaceAll(url, url[0:strings.Index(url, "/")+1], "")
213 }
214 parseddescription.WriteString("<a target=\"_blank\" href=\"" + url + "\">" + tagval(tt) + "</a> ")
215 }
216 }
217 case "img":
218 var (
219 uri, title string
220 )
221 for b, a := range token.Attr {
222 switch a.Key {
223 case "src":
224 if len(a.Val) > 9 && a.Val[8:9] == "e" {
225 uri = UrlBuilder("media", "emojitar", a.Val[37:len(a.Val)-4], "?type=e")
226 }
227 case "title":
228 title = a.Val
229 }
230 if title != "" {
231 for x := -1; x < b; x++ {
232 parseddescription.WriteString("<img src=\"" + uri + "\" title=\"" + title + "\">")
233 }
234 }
235 }
236 case "br", "li", "ul", "p", "b":
237 parseddescription.WriteString(token.String())
238 case "div":
239 parseddescription.WriteString("<p> ")
240 }
241 case html.TextToken:
242 parseddescription.Write(tt.Text())
243 }
244 }
144 } 245 }
145 246
146 return parseddescription.String() 247 return parseddescription.String()
@@ -234,7 +335,7 @@ func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) s
234 } 335 }
235 for _, data := range devs { 336 for _, data := range devs {
236 if !(data.NSFW && !CFG.Nsfw) { 337 if !(data.NSFW && !CFG.Nsfw) {
237 url := s.ParseMedia(data.Media) 338 url := ParseMedia(data.Media)
238 if s.Atom { 339 if s.Atom {
239 id := strconv.Itoa(data.ID) 340 id := strconv.Itoa(data.ID)
240 list.WriteString(`<entry><author><name>`) 341 list.WriteString(`<entry><author><name>`)
@@ -307,7 +408,6 @@ func (s skunkyart) DeviationList(devs []devianter.Deviation, content ...dlist) s
307 return list.String() 408 return list.String()
308} 409}
309 410
310// FIXME: первый комментарий не отображается.
311func (s skunkyart) ParseComments(c devianter.Comments) string { 411func (s skunkyart) ParseComments(c devianter.Comments) string {
312 var cmmts strings.Builder 412 var cmmts strings.Builder
313 replied := make(map[int]string) 413 replied := make(map[int]string)
@@ -354,7 +454,7 @@ func (s skunkyart) ParseComments(c devianter.Comments) string {
354 cmmts.WriteString(x.Posted.UTC().String()) 454 cmmts.WriteString(x.Posted.UTC().String())
355 cmmts.WriteString("]<p>") 455 cmmts.WriteString("]<p>")
356 456
357 cmmts.WriteString(x.Comment) 457 cmmts.WriteString(ParseDescription(x.TextContent))
358 cmmts.WriteString("<p>👍: ") 458 cmmts.WriteString("<p>👍: ")
359 cmmts.WriteString(strconv.Itoa(x.Likes)) 459 cmmts.WriteString(strconv.Itoa(x.Likes))
360 cmmts.WriteString(" ⏩: ") 460 cmmts.WriteString(" ⏩: ")
@@ -369,7 +469,7 @@ func (s skunkyart) ParseComments(c devianter.Comments) string {
369 return cmmts.String() 469 return cmmts.String()
370} 470}
371 471
372func (s skunkyart) ParseMedia(media devianter.Media) string { 472func ParseMedia(media devianter.Media) string {
373 url := devianter.UrlFromMedia(media) 473 url := devianter.UrlFromMedia(media)
374 if len(url) != 0 { 474 if len(url) != 0 {
375 url = url[21:] 475 url = url[21:]
app/wrapper.go +8 −4
@@ -127,7 +127,7 @@ func (s skunkyart) GRUser() {
127 case "cover_deviation": 127 case "cover_deviation":
128 group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation 128 group.About.BGMeta = x.ModuleData.CoverDeviation.Deviation
129 group.About.BGMeta.Url = s.ConvertDeviantArtUrlToSkunkyArt(group.About.BGMeta.Url) 129 group.About.BGMeta.Url = s.ConvertDeviantArtUrlToSkunkyArt(group.About.BGMeta.Url)
130 group.About.BG = s.ParseMedia(group.About.BGMeta.Media) 130 group.About.BG = ParseMedia(group.About.BGMeta.Media)
131 case "group_admins": 131 case "group_admins":
132 var htm strings.Builder 132 var htm strings.Builder
133 for _, z := range x.ModuleData.GroupAdmins.Results { 133 for _, z := range x.ModuleData.GroupAdmins.Results {
@@ -165,7 +165,7 @@ func (s skunkyart) GRUser() {
165 folders.WriteString(`<a href="`) 165 folders.WriteString(`<a href="`)
166 folders.WriteString(s.ConvertDeviantArtUrlToSkunkyArt(x.Thumb.Url)) 166 folders.WriteString(s.ConvertDeviantArtUrlToSkunkyArt(x.Thumb.Url))
167 folders.WriteString(`"><img loading="lazy" src="`) 167 folders.WriteString(`"><img loading="lazy" src="`)
168 folders.WriteString(s.ParseMedia(x.Thumb.Media)) 168 folders.WriteString(ParseMedia(x.Thumb.Media))
169 folders.WriteString(`" title="`) 169 folders.WriteString(`" title="`)
170 folders.WriteString(x.Thumb.Title) 170 folders.WriteString(x.Thumb.Title)
171 folders.WriteString(`"></a><br>`) 171 folders.WriteString(`"></a><br>`)
@@ -212,10 +212,14 @@ func (s skunkyart) Deviation(author, postname string) {
212 id := id_search[len(id_search)-1] 212 id := id_search[len(id_search)-1]
213 post.Post = devianter.DeviationFunc(id, author) 213 post.Post = devianter.DeviationFunc(id, author)
214 214
215 post.Post.Description = ParseDescription(post.Post.Deviation.TextContent) 215 if post.Post.Deviation.TextContent.Excerpt != "" {
216 post.Post.Description = ParseDescription(post.Post.Deviation.TextContent)
217 } else {
218 post.Post.Description = ParseDescription(post.Post.Deviation.Extended.DescriptionText)
219 }
216 // время публикации 220 // время публикации
217 post.StringTime = post.Post.Deviation.PublishedTime.UTC().String() 221 post.StringTime = post.Post.Deviation.PublishedTime.UTC().String()
218 post.Post.IMG = s.ParseMedia(post.Post.Deviation.Media) 222 post.Post.IMG = ParseMedia(post.Post.Deviation.Media)
219 for _, x := range post.Post.Deviation.Extended.RelatedContent { 223 for _, x := range post.Post.Deviation.Extended.RelatedContent {
220 if len(x.Deviations) != 0 { 224 if len(x.Deviations) != 0 {
221 post.Related = s.DeviationList(x.Deviations) 225 post.Related = s.DeviationList(x.Deviations)
css/skunky.css +28
@@ -60,6 +60,7 @@ form input, button, select {
60 color: rgb(160, 0, 147); 60 color: rgb(160, 0, 147);
61} 61}
62.content { 62.content {
63 align-items: center;
63 border-radius: 3px; 64 border-radius: 3px;
64 display: flex; 65 display: flex;
65 flex-wrap: wrap; 66 flex-wrap: wrap;
@@ -112,4 +113,31 @@ form input, button, select {
112 word-break: break-all; 113 word-break: break-all;
113 text-align: center; 114 text-align: center;
114 width: 5%; 115 width: 5%;
116}
117
118@media screen and (orientation: portrait) {
119 header {
120 scale: 155%;
121 justify-content: center;
122 }
123 .content {
124 margin: auto;
125 display: inherit;
126 scale: 100%;
127 }
128 .block {
129 max-width: 60%;
130 }
131}
132
133@media screen and (max-width: 1462px) {
134 .block {
135 max-width: 30%;
136 }
137}
138
139@media screen and (min-width: 788px) and (max-width: 884px) {
140 .block {
141 max-width: 35%;
142 }
115}\ No newline at end of file 143}\ No newline at end of file
go.mod +4 −1
@@ -4,4 +4,7 @@ go 1.22.3
4 4
5replace git.macaw.me/skunky/devianter v0.1.0 => /home/skunk/projects/devianter 5replace git.macaw.me/skunky/devianter v0.1.0 => /home/skunk/projects/devianter
6 6
7require git.macaw.me/skunky/devianter v0.1.0 7require (
8 git.macaw.me/skunky/devianter v0.1.0
9 golang.org/x/net v0.27.0
10)
go.sum +2
@@ -0,0 +1,2 @@
1golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
2golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
instances.json added +14
@@ -0,0 +1,14 @@
1{
2 "instances": [{
3 "urls": [{
4 "i2p": "http://skunky.i2p/art",
5 "tor": "http://skunky0wjkf8j8ajofgh98aOZjhu8f.onion/art",
6 "ygg": "http://[324:71e:281a:9ed3::fa11]/skunkyart",
7 "clearnet": "https://skunky.net/art"
8 }],
9 "settings": {
10 "nsfw": true,
11 "proxy": true
12 }
13 }]
14}\ No newline at end of file