Use image included in feed as feed icon
This commit is contained in:
parent
228bb62df4
commit
1aeb1b20da
8 changed files with 92 additions and 28 deletions
|
@ -52,6 +52,7 @@ type Feed struct {
|
|||
FetchViaProxy bool `json:"fetch_via_proxy"`
|
||||
Category *Category `json:"category,omitempty"`
|
||||
Entries Entries `json:"entries,omitempty"`
|
||||
IconURL string `json:"icon_url"`
|
||||
Icon *FeedIcon `json:"icon"`
|
||||
HideGlobally bool `json:"hide_globally"`
|
||||
UnreadCount int `json:"-"`
|
||||
|
|
|
@ -28,6 +28,7 @@ type atom10Feed struct {
|
|||
ID string `xml:"id"`
|
||||
Title atom10Text `xml:"title"`
|
||||
Authors atomAuthors `xml:"author"`
|
||||
Icon string `xml:"icon"`
|
||||
Links atomLinks `xml:"link"`
|
||||
Entries []atom10Entry `xml:"entry"`
|
||||
}
|
||||
|
@ -54,6 +55,8 @@ func (a *atom10Feed) Transform(baseURL string) *model.Feed {
|
|||
feed.Title = feed.SiteURL
|
||||
}
|
||||
|
||||
feed.IconURL = strings.TrimSpace(a.Icon)
|
||||
|
||||
for _, entry := range a.Entries {
|
||||
item := entry.Transform()
|
||||
entryURL, err := url.AbsoluteURL(feed.SiteURL, item.URL)
|
||||
|
|
|
@ -96,6 +96,7 @@ func CreateFeed(store *storage.Storage, userID int64, feedCreationRequest *model
|
|||
store,
|
||||
subscription.ID,
|
||||
subscription.SiteURL,
|
||||
subscription.IconURL,
|
||||
feedCreationRequest.UserAgent,
|
||||
feedCreationRequest.FetchViaProxy,
|
||||
feedCreationRequest.AllowSelfSignedCertificates,
|
||||
|
@ -189,6 +190,7 @@ func RefreshFeed(store *storage.Storage, userID, feedID int64) error {
|
|||
store,
|
||||
originalFeed.ID,
|
||||
originalFeed.SiteURL,
|
||||
updatedFeed.IconURL,
|
||||
originalFeed.UserAgent,
|
||||
originalFeed.FetchViaProxy,
|
||||
originalFeed.AllowSelfSignedCertificates,
|
||||
|
@ -208,9 +210,9 @@ func RefreshFeed(store *storage.Storage, userID, feedID int64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkFeedIcon(store *storage.Storage, feedID int64, websiteURL, userAgent string, fetchViaProxy, allowSelfSignedCertificates bool) {
|
||||
func checkFeedIcon(store *storage.Storage, feedID int64, websiteURL, iconURL, userAgent string, fetchViaProxy, allowSelfSignedCertificates bool) {
|
||||
if !store.HasIcon(feedID) {
|
||||
icon, err := icon.FindIcon(websiteURL, userAgent, fetchViaProxy, allowSelfSignedCertificates)
|
||||
icon, err := icon.FindIcon(websiteURL, iconURL, userAgent, fetchViaProxy, allowSelfSignedCertificates)
|
||||
if err != nil {
|
||||
logger.Debug(`[CheckFeedIcon] %v (feedID=%d websiteURL=%s)`, err, feedID, websiteURL)
|
||||
} else if icon == nil {
|
||||
|
|
|
@ -23,30 +23,32 @@ import (
|
|||
)
|
||||
|
||||
// FindIcon try to find the website's icon.
|
||||
func FindIcon(websiteURL, userAgent string, fetchViaProxy, allowSelfSignedCertificates bool) (*model.Icon, error) {
|
||||
rootURL := url.RootURL(websiteURL)
|
||||
logger.Debug("[FindIcon] Trying to find an icon: rootURL=%q websiteURL=%q userAgent=%q", rootURL, websiteURL, userAgent)
|
||||
func FindIcon(websiteURL, iconURL, userAgent string, fetchViaProxy, allowSelfSignedCertificates bool) (*model.Icon, error) {
|
||||
if iconURL == "" {
|
||||
rootURL := url.RootURL(websiteURL)
|
||||
logger.Debug("[FindIcon] Trying to find an icon: rootURL=%q websiteURL=%q userAgent=%q", rootURL, websiteURL, userAgent)
|
||||
|
||||
clt := client.NewClientWithConfig(rootURL, config.Opts)
|
||||
clt.WithUserAgent(userAgent)
|
||||
clt.AllowSelfSignedCertificates = allowSelfSignedCertificates
|
||||
clt := client.NewClientWithConfig(rootURL, config.Opts)
|
||||
clt.WithUserAgent(userAgent)
|
||||
clt.AllowSelfSignedCertificates = allowSelfSignedCertificates
|
||||
|
||||
if fetchViaProxy {
|
||||
clt.WithProxy()
|
||||
}
|
||||
if fetchViaProxy {
|
||||
clt.WithProxy()
|
||||
}
|
||||
|
||||
response, err := clt.Get()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("icon: unable to download website index page: %v", err)
|
||||
}
|
||||
response, err := clt.Get()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("icon: unable to download website index page: %v", err)
|
||||
}
|
||||
|
||||
if response.HasServerFailure() {
|
||||
return nil, fmt.Errorf("icon: unable to download website index page: status=%d", response.StatusCode)
|
||||
}
|
||||
if response.HasServerFailure() {
|
||||
return nil, fmt.Errorf("icon: unable to download website index page: status=%d", response.StatusCode)
|
||||
}
|
||||
|
||||
iconURL, err := parseDocument(rootURL, response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
iconURL, err = parseDocument(rootURL, response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(iconURL, "data:") {
|
||||
|
|
|
@ -17,13 +17,15 @@ import (
|
|||
)
|
||||
|
||||
type jsonFeed struct {
|
||||
Version string `json:"version"`
|
||||
Title string `json:"title"`
|
||||
SiteURL string `json:"home_page_url"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
Authors []jsonAuthor `json:"authors"`
|
||||
Author jsonAuthor `json:"author"`
|
||||
Items []jsonItem `json:"items"`
|
||||
Version string `json:"version"`
|
||||
Title string `json:"title"`
|
||||
SiteURL string `json:"home_page_url"`
|
||||
IconURL string `json:"icon"`
|
||||
FaviconURL string `json:"favicon"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
Authors []jsonAuthor `json:"authors"`
|
||||
Author jsonAuthor `json:"author"`
|
||||
Items []jsonItem `json:"items"`
|
||||
}
|
||||
|
||||
type jsonAuthor struct {
|
||||
|
@ -76,6 +78,12 @@ func (j *jsonFeed) Transform(baseURL string) *model.Feed {
|
|||
feed.SiteURL = j.SiteURL
|
||||
}
|
||||
|
||||
feed.IconURL = strings.TrimSpace(j.IconURL)
|
||||
|
||||
if feed.IconURL == "" {
|
||||
feed.IconURL = strings.TrimSpace(j.FaviconURL)
|
||||
}
|
||||
|
||||
feed.Title = strings.TrimSpace(j.Title)
|
||||
if feed.Title == "" {
|
||||
feed.Title = feed.SiteURL
|
||||
|
|
|
@ -15,6 +15,8 @@ func TestParseJsonFeed(t *testing.T) {
|
|||
data := `{
|
||||
"version": "https://jsonfeed.org/version/1",
|
||||
"title": "My Example Feed",
|
||||
"icon": "https://micro.blog/jsonfeed/avatar.jpg",
|
||||
"favicon": "https://micro.blog/jsonfeed/favicon.png",
|
||||
"home_page_url": "https://example.org/",
|
||||
"feed_url": "https://example.org/feed.json",
|
||||
"items": [
|
||||
|
@ -48,6 +50,10 @@ func TestParseJsonFeed(t *testing.T) {
|
|||
t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
|
||||
}
|
||||
|
||||
if feed.IconURL != "https://micro.blog/jsonfeed/avatar.jpg" {
|
||||
t.Errorf("Incorrect icon URL, got: %s", feed.IconURL)
|
||||
}
|
||||
|
||||
if len(feed.Entries) != 2 {
|
||||
t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
|
||||
}
|
||||
|
@ -617,3 +623,33 @@ func TestParseTags(t *testing.T) {
|
|||
t.Errorf("Incorrect entry tag, got %q instead of %q", result, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFavicon(t *testing.T) {
|
||||
data := `{
|
||||
"version": "https://jsonfeed.org/version/1",
|
||||
"title": "My Example Feed",
|
||||
"favicon": "https://micro.blog/jsonfeed/favicon.png",
|
||||
"home_page_url": "https://example.org/",
|
||||
"feed_url": "https://example.org/feed.json",
|
||||
"items": [
|
||||
{
|
||||
"id": "2",
|
||||
"content_text": "This is a second item.",
|
||||
"url": "https://example.org/second-item"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"content_html": "<p>Hello, world!</p>",
|
||||
"url": "https://example.org/initial-post"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if feed.IconURL != "https://micro.blog/jsonfeed/favicon.png" {
|
||||
t.Errorf("Incorrect icon URL, got: %s", feed.IconURL)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@ func TestParseRss2Sample(t *testing.T) {
|
|||
<title>Liftoff News</title>
|
||||
<link>http://liftoff.msfc.nasa.gov/</link>
|
||||
<description>Liftoff to Space Exploration.</description>
|
||||
<image>
|
||||
<url>http://liftoff.msfc.nasa.gov/HomePageXtra/MeatBall.gif</url>
|
||||
<title>NASA</title>
|
||||
<link>http://liftoff.msfc.nasa.gov/</link>
|
||||
</image>
|
||||
<language>en-us</language>
|
||||
<pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>
|
||||
<lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
|
||||
|
@ -71,6 +76,10 @@ func TestParseRss2Sample(t *testing.T) {
|
|||
t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
|
||||
}
|
||||
|
||||
if feed.IconURL != "http://liftoff.msfc.nasa.gov/HomePageXtra/MeatBall.gif" {
|
||||
t.Errorf("Incorrect image URL, got: %s", feed.IconURL)
|
||||
}
|
||||
|
||||
if len(feed.Entries) != 4 {
|
||||
t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries))
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ type rssFeed struct {
|
|||
Version string `xml:"version,attr"`
|
||||
Title string `xml:"channel>title"`
|
||||
Links []rssLink `xml:"channel>link"`
|
||||
ImageURL string `xml:"channel>image>url"`
|
||||
Language string `xml:"channel>language"`
|
||||
Description string `xml:"channel>description"`
|
||||
PubDate string `xml:"channel>pubDate"`
|
||||
|
@ -58,6 +59,8 @@ func (r *rssFeed) Transform(baseURL string) *model.Feed {
|
|||
feed.Title = feed.SiteURL
|
||||
}
|
||||
|
||||
feed.IconURL = strings.TrimSpace(r.ImageURL)
|
||||
|
||||
for _, item := range r.Items {
|
||||
entry := item.Transform()
|
||||
if entry.Author == "" {
|
||||
|
|
Loading…
Reference in a new issue