Skip to content

Commit

Permalink
正确解析友链的相对链接
Browse files Browse the repository at this point in the history
  • Loading branch information
movsb committed Jul 15, 2024
1 parent b7092c8 commit 6a0623a
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 21 deletions.
61 changes: 40 additions & 21 deletions service/modules/renderers/friends/friends.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,31 +97,50 @@ var svg = `<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg">
</svg>
`

// Name 是网站的名字,取首字符的大写作为图标。
func genSvgURL(name string) string {
// 预告填充成 SVG 首字母(因为可能加载失败)。
var first rune
if len(name) > 0 {
first, _ = utf8.DecodeRune([]byte(strings.ToUpper(name)))
}
letter := fmt.Sprintf(svg, string(first))
return `data:image/svg+xml;base64,` + base64.StdEncoding.EncodeToString([]byte(letter))
}

// TODO 更好的做法是 parse 页面,取 <link rel="favicon" ...
func resolveIconURL(siteURL, faviconURL string) (string, error) {
us, err := url.Parse(siteURL)
if err != nil {
return ``, err
}

// 如果没指定,默认用 favicon.ico
if faviconURL == "" {
faviconURL = us.JoinPath(`/favicon.ico`).String()
}

uf, err := url.Parse(faviconURL)
if err != nil {
return ``, err
}

uf = us.ResolveReference(uf)
return uf.String(), nil
}

func (f *Friends) prepareIconURL(ctx context.Context, fs []*Friend) {
for i, fr := range fs {
if fr.Icon == "" {
u2, err := url.Parse(fr.URL)
if err == nil {
if u2.Path == "" {
u2.Path = "/"
}
fr.Icon = u2.JoinPath(`/favicon.ico`).String()
}
}
if fr.Icon == "" {
continue
}
fr.iconDataURL = genSvgURL(fr.Name)

// 预告填充成 SVG 首字母(因为可能加载失败)。
var first rune
if len(fr.Name) > 0 {
first, _ = utf8.DecodeRune([]byte(strings.ToUpper(fr.Name)))
u, err := resolveIconURL(fr.URL, fr.Icon)
if err != nil {
log.Println(err)
continue
}
letter := fmt.Sprintf(svg, string(first))
fr.iconDataURL = `data:image/svg+xml;base64,` + base64.StdEncoding.EncodeToString([]byte(letter))

go func(i int, fr *Friend) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fr.Icon, nil)
go func(i int, u string, fr *Friend) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
log.Println(`头像请求失败:`, err)
return
Expand All @@ -146,6 +165,6 @@ func (f *Friends) prepareIconURL(ctx context.Context, fs []*Friend) {
}
uri := fmt.Sprintf(`data:%s;base64,%s`, contentType, base64.StdEncoding.EncodeToString(body))
fr.iconDataURL = uri
}(i, fr)
}(i, u, fr)
}
}
60 changes: 60 additions & 0 deletions service/modules/renderers/friends/friends_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package friends

import "testing"

func TestResolveURL(t *testing.T) {
testCases := []struct {
SiteURL string
FaviconURL string
Want string
}{
{
SiteURL: `https://blog.twofei.com`,
FaviconURL: ``,
Want: `https://blog.twofei.com/favicon.ico`,
},
{
SiteURL: `https://blog.twofei.com`,
FaviconURL: `https://blog.twofei.com/favicon.avif`,
Want: `https://blog.twofei.com/favicon.avif`,
},
{
SiteURL: `https://blog.twofei.com`,
FaviconURL: `/favicon.avif`,
Want: `https://blog.twofei.com/favicon.avif`,
},
{
SiteURL: `https://blog.twofei.com`,
FaviconURL: `favicon.avif`,
Want: `https://blog.twofei.com/favicon.avif`,
},
{
SiteURL: `https://blog.twofei.com/sub`,
FaviconURL: `favicon.avif`,
Want: `https://blog.twofei.com/favicon.avif`,
},
{
SiteURL: `https://blog.twofei.com/sub`,
FaviconURL: `/favicon.avif`,
Want: `https://blog.twofei.com/favicon.avif`,
},
{
SiteURL: `https://blog.twofei.com/sub/`,
FaviconURL: `favicon.avif`,
Want: `https://blog.twofei.com/sub/favicon.avif`,
},
{
SiteURL: `https://blog.twofei.com/sub/`,
FaviconURL: `/favicon.avif`,
Want: `https://blog.twofei.com/favicon.avif`,
},
}

for i, tc := range testCases {
u, err := resolveIconURL(tc.SiteURL, tc.FaviconURL)
if err != nil || u != tc.Want {
t.Errorf(`error: %d: %s %s %s`, i, tc.SiteURL, tc.FaviconURL, tc.Want)
continue
}
}
}

0 comments on commit 6a0623a

Please sign in to comment.