Support emoji, hashtags, user mentions, URLs and replys
This commit is contained in:
parent
09100849a9
commit
edf91667c8
2
go.mod
2
go.mod
@ -9,6 +9,6 @@ require (
|
|||||||
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect
|
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect
|
||||||
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect
|
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect
|
||||||
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect
|
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect
|
||||||
github.com/joho/godotenv v1.3.0 // indirect
|
github.com/joho/godotenv v1.3.0
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
|
||||||
)
|
)
|
||||||
|
27
main.go
27
main.go
@ -8,6 +8,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -67,6 +68,28 @@ func getTweet(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`[\x{1F300}-\x{1F6FF}]`)
|
||||||
|
emojis := re.FindAllString(tweet.FullText, -1)
|
||||||
|
|
||||||
|
emojiCount := 0
|
||||||
|
for _, emoji := range emojis {
|
||||||
|
emojiCount += len([]byte(emoji)) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(tweet.FullText)
|
||||||
|
|
||||||
|
tweet.FullText = tweet.FullText[tweet.DisplayTextRange[0] : tweet.DisplayTextRange[1]+emojiCount]
|
||||||
|
|
||||||
|
for _, user := range tweet.Entities.User_mentions {
|
||||||
|
tweet.FullText = strings.ReplaceAll(tweet.FullText, "@"+user.Screen_name, fmt.Sprintf("<a href=\"https://twitter.com/%s/\">@%s</a>", user.Screen_name, user.Screen_name))
|
||||||
|
}
|
||||||
|
for _, url := range tweet.Entities.Urls {
|
||||||
|
tweet.FullText = strings.ReplaceAll(tweet.FullText, url.Url, fmt.Sprintf("<a href=\"https://twitter.com/%s/\">%s</a>", url.Expanded_url, url.Display_url))
|
||||||
|
}
|
||||||
|
for _, hashtag := range tweet.Entities.Hashtags {
|
||||||
|
tweet.FullText = strings.ReplaceAll(tweet.FullText, "#"+hashtag.Text, fmt.Sprintf("<a href=\"https://twitter.com/hashtag/%s\">#%s</a>", hashtag.Text, hashtag.Text))
|
||||||
|
}
|
||||||
|
|
||||||
templateFuncs := template.FuncMap{
|
templateFuncs := template.FuncMap{
|
||||||
"base64": func(url string) string {
|
"base64": func(url string) string {
|
||||||
res, err := http.Get(url)
|
res, err := http.Get(url)
|
||||||
@ -85,6 +108,9 @@ func getTweet(w http.ResponseWriter, r *http.Request) {
|
|||||||
t, _ := time.Parse(tweetDateLayout, date)
|
t, _ := time.Parse(tweetDateLayout, date)
|
||||||
return t.Format("3:04 PM · Jan 2, 2006")
|
return t.Format("3:04 PM · Jan 2, 2006")
|
||||||
},
|
},
|
||||||
|
"html": func(in string) template.HTML {
|
||||||
|
return template.HTML(in)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
t := template.Must(
|
t := template.Must(
|
||||||
@ -93,6 +119,7 @@ func getTweet(w http.ResponseWriter, r *http.Request) {
|
|||||||
ParseFiles("tweet.svg.tmpl"))
|
ParseFiles("tweet.svg.tmpl"))
|
||||||
|
|
||||||
w.Header().Set("Content-type", "image/svg+xml")
|
w.Header().Set("Content-type", "image/svg+xml")
|
||||||
|
w.Header().Set("content-encoding", "br")
|
||||||
err = t.Execute(w, tweet)
|
err = t.Execute(w, tweet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
.tweetsvg{clear:none;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;}
|
.tweetsvg{clear:none;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;}
|
||||||
.tweetsvg.text{font-size: 23px;}
|
.tweetsvg.text{font-size: 23px;}
|
||||||
a.tweetsvg{color: rgb(27, 149, 224); text-decoration:none;}
|
a.tweetsvg{color: rgb(27, 149, 224); text-decoration:none;}
|
||||||
|
.tweetsvg a { color: #1da1f2; }
|
||||||
blockquote.tweetsvg{margin:1px; background-color:#fefefe; border-radius:2%; border-style:solid; border-width:.1em; border-color:#ddd; padding:1em; font-family:sans; width:29rem}
|
blockquote.tweetsvg{margin:1px; background-color:#fefefe; border-radius:2%; border-style:solid; border-width:.1em; border-color:#ddd; padding:1em; font-family:sans; width:29rem}
|
||||||
.avatar-tweetsvg{float:left; width:4rem; height:4rem; border-radius:50%;margin-right:.5rem;;margin-bottom:.5rem;border-style: solid; border-width:.1em; border-color:#ddd;}
|
.avatar-tweetsvg{float:left; width:4rem; height:4rem; border-radius:50%;margin-right:.5rem;;margin-bottom:.5rem;border-style: solid; border-width:.1em; border-color:#ddd;}
|
||||||
h1.tweetsvg{margin:0;font-size:15px;text-decoration:none;color:#000;}
|
h1.tweetsvg{margin:0;font-size:15px;text-decoration:none;color:#000;}
|
||||||
@ -12,6 +13,7 @@
|
|||||||
hr.tweetsvg{color:#ddd;}
|
hr.tweetsvg{color:#ddd;}
|
||||||
.media-tweetsvg{border-radius:2%; max-width:100%;border-radius: 2%; border-style: solid; border-width: .1em; border-color: #ddd;}
|
.media-tweetsvg{border-radius:2%; max-width:100%;border-radius: 2%; border-style: solid; border-width: .1em; border-color: #ddd;}
|
||||||
time.tweetsvg{font-size:15px;margin:0;margin-left: 2px;padding-bottom:1rem;color:rgb(101, 119, 134);text-decoration:none;}
|
time.tweetsvg{font-size:15px;margin:0;margin-left: 2px;padding-bottom:1rem;color:rgb(101, 119, 134);text-decoration:none;}
|
||||||
|
.tweetsvg.reply{font-size:15px;color:rgb(110, 118, 125);}
|
||||||
</style>
|
</style>
|
||||||
<blockquote class="tweetsvg" xmlns="http://www.w3.org/1999/xhtml">
|
<blockquote class="tweetsvg" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<a class="tweetsvg" href="https://twitter.com/{{ .User.ScreenName }}/"><img class="avatar-tweetsvg" alt="" src="data:image/jpeg;base64,{{ base64 .User.ProfileImageUrlHttps }}" /></a>
|
<a class="tweetsvg" href="https://twitter.com/{{ .User.ScreenName }}/"><img class="avatar-tweetsvg" alt="" src="data:image/jpeg;base64,{{ base64 .User.ProfileImageUrlHttps }}" /></a>
|
||||||
@ -20,7 +22,11 @@
|
|||||||
|
|
||||||
<a class="tweetsvg" href="https://twitter.com/{{ .User.ScreenName }}/"><h2 class="tweetsvg">@{{ .User.ScreenName }}</h2></a>
|
<a class="tweetsvg" href="https://twitter.com/{{ .User.ScreenName }}/"><h2 class="tweetsvg">@{{ .User.ScreenName }}</h2></a>
|
||||||
|
|
||||||
<p class="tweetsvg text">{{ .Text }}</p>
|
{{ if .InReplyToScreenName }}
|
||||||
|
<p class="tweetsvg reply">Replying to <a href="https://twitter.com/{{ .InReplyToScreenName }}/">@{{ .InReplyToScreenName }}</a></p>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<p class="tweetsvg text">{{ html .FullText }}</p>
|
||||||
|
|
||||||
{{ if .ExtendedEntities }}
|
{{ if .ExtendedEntities }}
|
||||||
{{ range .ExtendedEntities.Media }}
|
{{ range .ExtendedEntities.Media }}
|
||||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.5 KiB |
Loading…
Reference in New Issue
Block a user