diff --git a/service/modules/renderers/friends/friends.go b/service/modules/renderers/friends/friends.go
index 48dc00af..c1b44d9f 100644
--- a/service/modules/renderers/friends/friends.go
+++ b/service/modules/renderers/friends/friends.go
@@ -97,31 +97,50 @@ var 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 页面,取 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
@@ -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)
}
}
diff --git a/service/modules/renderers/friends/friends_test.go b/service/modules/renderers/friends/friends_test.go
new file mode 100644
index 00000000..257f7bfc
--- /dev/null
+++ b/service/modules/renderers/friends/friends_test.go
@@ -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
+ }
+ }
+}