package app import ( "encoding/json" "strconv" "strings" "git.macaw.me/skunky/devianter" "golang.org/x/net/html" ) func (s skunkyart) ParseComments(c devianter.Comments) string { var cmmts strings.Builder replied := make(map[int]string) cmmts.WriteString("
Comments: ") cmmts.WriteString(strconv.Itoa(c.Total)) cmmts.WriteString("") for _, x := range c.Thread { replied[x.ID] = x.User.Username cmmts.WriteString(`

`) cmmts.WriteString(x.User.Username) cmmts.WriteString(" ") if x.Parent > 0 { cmmts.WriteString(` In reply to `) if replied[x.Parent] == "" { cmmts.WriteString("???") } else { cmmts.WriteString(replied[x.Parent]) } cmmts.WriteString("") } cmmts.WriteString(" [") cmmts.WriteString(x.Posted.UTC().String()) cmmts.WriteString("]

") cmmts.WriteString(ParseDescription(x.TextContent)) cmmts.WriteString("

👍: ") cmmts.WriteString(strconv.Itoa(x.Likes)) cmmts.WriteString(" ⏩: ") cmmts.WriteString(strconv.Itoa(x.Replies)) cmmts.WriteString("

\n") } cmmts.WriteString(s.NavBase(DeviationList{ Pages: 0, More: c.HasMore, })) cmmts.WriteString("
") return cmmts.String() } func (s skunkyart) DeviationList(devs []devianter.Deviation, allowAtom bool, content ...DeviationList) string { if s.Atom && s.Page > 1 { s.ReturnHTTPError(400) return "" } var list, listContent strings.Builder for i, l := 0, len(devs); i < l; i++ { data := &devs[i] if preview, fullview := ParseMedia(data.Media, 320), ParseMedia(data.Media); !(data.NSFW && !CFG.Nsfw) { if allowAtom && s.Atom { id := strconv.Itoa(data.ID) listContent.WriteString(``) listContent.WriteString(data.Author.Username) listContent.WriteString(``) listContent.WriteString(data.Title) listContent.WriteString(``) listContent.WriteString(id) listContent.WriteString(``) listContent.WriteString(data.PublishedTime.UTC().Format("Mon, 02 Jan 2006 15:04:05 -0700")) listContent.WriteString(``) listContent.WriteString(``) listContent.WriteString(data.Title) listContent.WriteString(`

`) listContent.WriteString(ParseDescription(data.TextContent)) listContent.WriteString(`

`) } else { listContent.WriteString(`
`) if fullview != "" && preview != "" { listContent.WriteString(``) } else { listContent.WriteString(`

[ TEXT ]

`) } listContent.WriteString(`
`) listContent.WriteString(data.Author.Username) listContent.WriteString(" - ") listContent.WriteString(data.Title) if data.NSFW { listContent.WriteString(` [NSFW]`) } if data.AI { listContent.WriteString(" [🤖]") } if data.DD { listContent.WriteString(` [DD]`) } listContent.WriteString("
") } } } if allowAtom && s.Atom { list.WriteString(``) list.WriteString(``) if s.Type == 0 { list.WriteString("Daily Deviations") } else if s.Type == 'g' && len(devs) != 0 { list.WriteString(devs[0].Author.Username) } else { list.WriteString("SkunkyArt") } list.WriteString(``) list.WriteString(``) list.WriteString(listContent.String()) list.WriteString("") wr(s.Writer, list.String()) } else { list.WriteString(`
`) list.WriteString(listContent.String()) list.WriteString("
") if content != nil { list.WriteString(s.NavBase(content[0])) } } return list.String() } /* DESCRIPTION/COMMENT PARSER */ type text struct { TXT string TXT_RAW string From int To int } func ParseDescription(dscr devianter.Text) string { var parsedDescription strings.Builder TagBuilder := func(content string, tags ...string) string { l := len(tags) for x := 0; x < l; x++ { var htm strings.Builder htm.WriteString("<") htm.WriteString(tags[x]) htm.WriteString(">") htm.WriteString(content) htm.WriteString("") content = htm.String() } return content } DeleteTrackingFromUrl := func(url string) string { if len(url) > 42 && url[:42] == "https://www.deviantart.com/users/outgoing?" { url = url[42:] } return url } if description, dl := dscr.Html.Markup, len(dscr.Html.Markup); dl != 0 && description[0] == '{' && description[dl-1] == '}' { var descr struct { Blocks []struct { Text, Type string InlineStyleRanges []struct { Offset, Length int Style string } EntityRanges []struct { Offset, Length int Key int } Data struct { TextAlignment string } } EntityMap map[string]struct { Type string Data struct { Url string Config struct { Aligment string Width int } Data devianter.Deviation } } } e := json.Unmarshal([]byte(description), &descr) try(e) entities := make(map[int]devianter.Deviation) urls := make(map[int]string) for n, x := range descr.EntityMap { num, _ := strconv.Atoi(n) if x.Data.Url != "" { urls[num] = DeleteTrackingFromUrl(x.Data.Url) } entities[num] = x.Data.Data } for _, x := range descr.Blocks { Styles := make([]text, len(x.InlineStyleRanges)) if len(x.InlineStyleRanges) != 0 { var tags = make(map[int][]string) for n, rngs := range x.InlineStyleRanges { Styles := &Styles[n] switch rngs.Style { case "BOLD": rngs.Style = "b" case "UNDERLINE": rngs.Style = "u" case "ITALIC": rngs.Style = "i" } Styles.From = rngs.Offset Styles.To = rngs.Offset + rngs.Length FT := Styles.From * Styles.To tags[FT] = append(tags[FT], rngs.Style) } for n := 0; n < len(Styles); n++ { Styles := &Styles[n] Styles.TXT_RAW = x.Text[Styles.From:Styles.To] Styles.TXT = TagBuilder(Styles.TXT_RAW, tags[Styles.From*Styles.To]...) } } switch x.Type { case "atomic": if len(x.EntityRanges) != 0 { d := entities[x.EntityRanges[0].Key] parsedDescription.WriteString(``) } case "unstyled": if l := len(Styles); l != 0 { for n, r := range Styles { var tag string if x.Type == "header-two" { tag = "h2" } parsedDescription.WriteString(x.Text[:r.From]) if len(urls) != 0 && len(x.EntityRanges) != 0 { ra := &x.EntityRanges[0] parsedDescription.WriteString(``) parsedDescription.WriteString(r.TXT) parsedDescription.WriteString(``) } else if l > n+1 { parsedDescription.WriteString(r.TXT) } parsedDescription.WriteString(TagBuilder(tag, x.Text[r.To:])) } } else { parsedDescription.WriteString(x.Text) } } parsedDescription.WriteString("
") } } else if dl != 0 { for tt := html.NewTokenizer(strings.NewReader(dscr.Html.Markup)); ; { switch tt.Next() { case html.ErrorToken: return parsedDescription.String() case html.StartTagToken, html.EndTagToken, html.SelfClosingTagToken: token := tt.Token() switch token.Data { case "a": for _, a := range token.Attr { if a.Key == "href" { url := DeleteTrackingFromUrl(a.Val) parsedDescription.WriteString(``) parsedDescription.WriteString(GetValueOfTag(tt)) parsedDescription.WriteString(" ") } } case "img": var uri, title string for b, a := range token.Attr { switch a.Key { case "src": if len(a.Val) > 9 && a.Val[8:9] == "e" { uri = UrlBuilder("media", "emojitar", a.Val[37:len(a.Val)-4], "?type=e") } case "title": title = a.Val } if title != "" { for x := -1; x < b; x++ { parsedDescription.WriteString(``) } } } case "br", "li", "ul", "p", "b": parsedDescription.WriteString(token.String()) case "div": parsedDescription.WriteString("

") } case html.TextToken: parsedDescription.Write(tt.Text()) } } } return parsedDescription.String() }