diff --git a/main.go b/main.go index f31dcc4211b0d0d1dde0724003d244192e2daf44..b0579e31ac228ee6559d3017f7731740da864b01 100644 --- a/main.go +++ b/main.go @@ -38,74 +38,95 @@ type OEmbed struct { } type InternalData struct { - url string - - oembed_url string - - twitter_card string - twitter_site string - twitter_site_id string - twitter_creator string - twitter_creator_id string - twitter_description string - twitter_title string - twitter_image string - twitter_image_alt string - twitter_player string - twitter_player_width string - twitter_player_height string - twitter_player_stream string - twitter_app_name_iphone string - twitter_app_id_iphone string - twitter_app_url_iphone string - twitter_app_name_ipad string - twitter_app_id_ipad string - twitter_app_url_ipad string - twitter_app_name_googleplay string - twitter_app_id_googleplay string - twitter_app_url_googleplay string - twitter_label1 string - twitter_data1 string - twitter_label2 string - twitter_data2 string - - og_url string - og_title string - og_description string - og_type string - og_locale string - - og_video string - og_video_url string - og_video_secure_url string - og_video_type string - og_video_width string - og_video_height string - - og_image string - og_image_url string - og_image_secure_url string - og_image_type string - og_image_width string - og_image_height string - - og_audio string - og_audio_url string - og_audio_secure_url string - og_audio_type string - - og_site_name string - - article_author string - article_published_time string - - meta_title string - meta_description string - meta_author string - meta_theme_color string - link_favicon string - link_author string - title string + url *url.URL + + oembedUrl string + + twitterCard string + twitterSite string + twitterSiteId string + twitterCreator string + twitterCreatorId string + twitterDescription string + twitterTitle string + twitterImage string + twitterImageAlt string + twitterPlayer string + twitterPlayerWidth string + twitterPlayerHeight string + twitterPlayerStream string + twitterAppNameIphone string + twitterAppIdIphone string + twitterAppUrlIphone string + twitterAppNameIpad string + twitterAppIdIpad string + twitterAppUrlIpad string + twitterAppNameGoogleplay string + twitterAppIdGoogleplay string + twitterAppUrlGoogleplay string + twitterLabel1 string + twitterData1 string + twitterLabel2 string + twitterData2 string + + ogUrl string + ogTitle string + ogDescription string + ogType string + ogLocale string + + ogVideo string + ogVideoUrl string + ogVideoSecureUrl string + ogVideoType string + ogVideoWidth string + ogVideoHeight string + + ogImage string + ogImageUrl string + ogImageSecureUrl string + ogImageType string + ogImageWidth string + ogImageHeight string + + ogAudio string + ogAudioUrl string + ogAudioSecureUrl string + ogAudioType string + + ogSiteName string + + articleAuthor string + articlePublisher string + articlePublishedTime string + + soundcloudUser string + soundcloudPlayCount string + soundcloudDownloadCount string + soundcloudCommentsCount string + soundcloudLikeCount string + soundcloudSoundCount string + soundcloudFollowerCount string + + metaTitle string + metaDescription string + metaAuthor string + metaThemeColor string + linkFavicon string + linkAuthor string + title string + + urlProviderIconIco string + urlProviderIconPng string + + urlProviderOgSiteName string + + urlProviderMetaThemeColor string + urlProviderMetaTitle string + urlProviderLinkFavicon string + urlProviderTitle string + + rawType string } type DataField struct { @@ -124,8 +145,8 @@ type Data struct { Text string `json:"text"` Fields []DataField `json:"fields"` ImageUrl string `json:"image_url"` - LargeImage bool `json:"large_image"` - Types []string `json:"types"` + Type string `json:"type"` + Player string `json:"player"` ThumbUrl string `json:"thumb_url"` Footer string `json:"footer"` FooterIcon string `json:"footer_icon"` @@ -142,69 +163,129 @@ func coalesce(list []string) string { return "" } -func buildData(in InternalData, oEmbed OEmbed) (out Data) { - base, _ := url.ParseRequestURI(in.url) - resolve := func(path string) string { - if path == "" || base == nil { - return "" - } - relative, err := url.Parse(path) - if err != nil { - return "" +func coalesceFilter(condition func(string) bool, list []string) string { + for _, str := range list { + str = strings.TrimSpace(str) + if str != "" && condition(str) { + return str } - absolute := base.ResolveReference(relative) - return absolute.String() } + return "" +} + +func isUrl(value string) bool { + if strings.Contains(value, "://") { + return true + } + if strings.HasPrefix(value, "/") { + return true + } + return false +} + +func isNotUrl(value string) bool { + return !isUrl(value) +} + +func resolve(base *url.URL, path string) string { + if path == "" || base == nil { + return "" + } + relative, err := url.Parse(path) + if err != nil { + return "" + } + absolute := base.ResolveReference(relative) + return absolute.String() +} +func buildData(in InternalData, oEmbed OEmbed, providerFallbacks []func(*InternalData)) (out Data) { out = Data{} - out.TitleLink = in.url - out.Title = coalesce([]string{in.twitter_title, in.og_title, in.meta_title, in.title}) - out.Text = coalesce([]string{in.twitter_description, in.og_description, in.meta_description}) - out.AuthorName = coalesce([]string{oEmbed.AuthorName, in.meta_author}) - out.AuthorLink = resolve(coalesce([]string{oEmbed.AuthorUrl, in.article_author, in.link_author})) - out.Color = coalesce([]string{in.meta_theme_color}) - out.Footer = coalesce([]string{oEmbed.ProviderName, in.og_site_name}) - out.FooterIcon = resolve(coalesce([]string{in.link_favicon})) + out.TitleLink = in.url.String() + out.Title = coalesce([]string{in.twitterTitle, in.ogTitle, in.metaTitle, in.title}) + out.Text = coalesce([]string{in.twitterDescription, in.ogDescription, in.metaDescription}) + out.AuthorName = coalesceFilter(isNotUrl, []string{oEmbed.AuthorName, in.articleAuthor, in.articlePublisher, in.metaAuthor}) + out.AuthorLink = resolve(in.url, coalesceFilter(isUrl, []string{oEmbed.AuthorUrl, in.articleAuthor, in.articlePublisher, in.soundcloudUser, in.linkAuthor})) + + for _, fallback := range providerFallbacks { + out.Color = coalesce([]string{in.metaThemeColor, in.urlProviderMetaThemeColor}) + out.Footer = coalesce([]string{oEmbed.ProviderName, in.ogSiteName, in.urlProviderOgSiteName, in.urlProviderMetaTitle, in.urlProviderTitle}) + out.FooterIcon = resolve(in.url, coalesce([]string{in.linkFavicon, in.urlProviderLinkFavicon, in.urlProviderIconPng, in.urlProviderIconIco})) + if out.Footer != "" && out.FooterIcon != "" { + break + } + fallback(&in) + } var largeImages []string var smallImages []string - if in.twitter_card == "summary" || in.twitter_card == "summary_large_image" { - largeImages = append(largeImages, in.twitter_image) + if in.twitterCard == "summary" || in.twitterCard == "summary_large_image" { + largeImages = append(largeImages, in.twitterImage) } else { - smallImages = append(smallImages, in.twitter_image) + smallImages = append(smallImages, in.twitterImage) } - largeImages = append(largeImages, in.og_image) - smallImages = append(smallImages, in.link_favicon) - - largeTypes := []string{ - "video", - "video.other", - "article", - "summary_large_image", - "player", + largeImages = append(largeImages, in.ogImage) + smallImages = append(smallImages, in.ogImage) + if in.rawType == "image" { + largeImages = append(largeImages, in.url.String()) + } + // Only use favicon as thumbnail icon if we don’t already use it for the footer + if out.Footer == "" { + smallImages = append(smallImages, in.linkFavicon) } - isLargeImage := func (format string) bool { - for _, t := range largeTypes { - if t == format { - return true + hasType := func(formats []string, types []string) bool { + for _, format := range formats { + for _, t := range types { + if t == format { + return true + } } } return false } - out.LargeImage = isLargeImage(oEmbed.Type) || isLargeImage(in.og_type) || isLargeImage(in.twitter_card) + if in.rawType == "video" || in.rawType == "audio" { + out.Player = in.url.String() + out.Type = "player" + } else if in.rawType == "image" { + out.Type = "image" + } else { + if hasType([]string{oEmbed.Type, in.twitterCard, in.ogType}, []string{"article", "summary_large_image", "image"}) { + out.Type = "image" + } else if hasType([]string{oEmbed.Type, in.twitterCard, in.ogType}, []string{"player", "video", "video.other", "music", "music.song", "audio"}) { + out.Type = "player" + } + + if out.Type == "player" { + out.Player = coalesce([]string{in.twitterPlayer, in.ogVideoSecureUrl, in.ogVideoUrl, in.ogAudioSecureUrl, in.ogAudioUrl}) + } + } + if out.Type == "" { + out.Type = "article" + } + + out.ThumbUrl = resolve(in.url, coalesce(smallImages)) + out.ImageUrl = resolve(in.url, coalesce(largeImages)) - types := []string{} - for _, format := range []string{oEmbed.Type, in.og_type, in.twitter_card} { - if format != "" { - types = append(types, format) + buildField := func(title string, value string) { + const MaxShortFieldLength = 32 + value = strings.TrimSpace(value) + if value != "" && value != "0" { + out.Fields = append(out.Fields, DataField{ + Title: title, + Value: value, + Short: len(value) < MaxShortFieldLength && len(title) < MaxShortFieldLength, + }) } } - out.Types = types - out.ThumbUrl = resolve(coalesce(smallImages)) - out.ImageUrl = resolve(coalesce(largeImages)) + buildField("Play Count", in.soundcloudPlayCount) + buildField("Download Count", in.soundcloudDownloadCount) + buildField("Comments Count", in.soundcloudCommentsCount) + buildField("Like Count", in.soundcloudLikeCount) + buildField("Sound Count", in.soundcloudSoundCount) + buildField("Follower Count", in.soundcloudFollowerCount) return } @@ -214,287 +295,389 @@ func main() { matchers := map[string]func(*InternalData, string, string){} matchers["meta/twitter:card"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_card = content + internalData.twitterCard = content } matchers["meta/twitter:site"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_site = content + internalData.twitterSite = content } matchers["meta/twitter:site:id"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_site_id = content + internalData.twitterSiteId = content } matchers["meta/twitter:creator"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_creator = content + internalData.twitterCreator = content } matchers["meta/twitter:creator:id"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_creator_id = content + internalData.twitterCreatorId = content } matchers["meta/twitter:description"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_description = content + internalData.twitterDescription = content } matchers["meta/twitter:title"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_title = content + internalData.twitterTitle = content } matchers["meta/twitter:image"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_image = content + internalData.twitterImage = content } matchers["meta/twitter:image:src"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_image = content + internalData.twitterImage = content } matchers["meta/twitter:image:alt"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_image_alt = content + internalData.twitterImageAlt = content } matchers["meta/twitter:player"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_player = content + internalData.twitterPlayer = content } matchers["meta/twitter:player:width"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_player_width = content + internalData.twitterPlayerWidth = content } matchers["meta/twitter:player:height"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_player_height = content + internalData.twitterPlayerHeight = content } matchers["meta/twitter:player:stream"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_player_stream = content + internalData.twitterPlayerStream = content } matchers["meta/twitter:app:name:iphone"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_name_iphone = content + internalData.twitterAppNameIphone = content } matchers["meta/twitter:app:id:iphone"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_id_iphone = content + internalData.twitterAppIdIphone = content } matchers["meta/twitter:app:url:iphone"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_url_iphone = content + internalData.twitterAppUrlIphone = content } matchers["meta/twitter:app:name:ipad"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_name_ipad = content + internalData.twitterAppNameIpad = content } matchers["meta/twitter:app:id:ipad"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_id_ipad = content + internalData.twitterAppIdIpad = content } matchers["meta/twitter:app:url:ipad"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_url_ipad = content + internalData.twitterAppUrlIpad = content } matchers["meta/twitter:app:name:googleplay"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_name_googleplay = content + internalData.twitterAppNameGoogleplay = content } matchers["meta/twitter:app:id:googleplay"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_id_googleplay = content + internalData.twitterAppIdGoogleplay = content } matchers["meta/twitter:app:url:googleplay"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_app_url_googleplay = content + internalData.twitterAppUrlGoogleplay = content } matchers["meta/twitter:label1"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_label1 = content + internalData.twitterLabel1 = content } matchers["meta/twitter:data1"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_data1 = content + internalData.twitterData1 = content } matchers["meta/twitter:label2"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_label2 = content + internalData.twitterLabel2 = content } matchers["meta/twitter:data2"] = func(internalData *InternalData, content string, extra string) { - internalData.twitter_data2 = content + internalData.twitterData2 = content } matchers["meta/og:url"] = func(internalData *InternalData, content string, extra string) { - internalData.og_url = content + internalData.ogUrl = content } matchers["meta/og:title"] = func(internalData *InternalData, content string, extra string) { - internalData.og_title = content + internalData.ogTitle = content } matchers["meta/og:description"] = func(internalData *InternalData, content string, extra string) { - internalData.og_description = content + internalData.ogDescription = content } matchers["meta/og:type"] = func(internalData *InternalData, content string, extra string) { - internalData.og_type = content + internalData.ogType = content } matchers["meta/og:locale"] = func(internalData *InternalData, content string, extra string) { - internalData.og_locale = content + internalData.ogLocale = content } matchers["meta/og:video"] = func(internalData *InternalData, content string, extra string) { - internalData.og_video = content + internalData.ogVideo = content } matchers["meta/og:video:url"] = func(internalData *InternalData, content string, extra string) { - internalData.og_video_url = content + internalData.ogVideoUrl = content } matchers["meta/og:video:secure_url"] = func(internalData *InternalData, content string, extra string) { - internalData.og_video_secure_url = content + internalData.ogVideoSecureUrl = content } matchers["meta/og:video:type"] = func(internalData *InternalData, content string, extra string) { - internalData.og_video_type = content + internalData.ogVideoType = content } matchers["meta/og:video:width"] = func(internalData *InternalData, content string, extra string) { - internalData.og_video_width = content + internalData.ogVideoWidth = content } matchers["meta/og:video:height"] = func(internalData *InternalData, content string, extra string) { - internalData.og_video_height = content + internalData.ogVideoHeight = content } matchers["meta/og:image"] = func(internalData *InternalData, content string, extra string) { - internalData.og_image = content + internalData.ogImage = content } matchers["meta/og:image:url"] = func(internalData *InternalData, content string, extra string) { - internalData.og_image_url = content + internalData.ogImageUrl = content } matchers["meta/og:image:secure_url"] = func(internalData *InternalData, content string, extra string) { - internalData.og_image_secure_url = content + internalData.ogImageSecureUrl = content } matchers["meta/og:image:type"] = func(internalData *InternalData, content string, extra string) { - internalData.og_image_type = content + internalData.ogImageType = content } matchers["meta/og:image:width"] = func(internalData *InternalData, content string, extra string) { - internalData.og_image_width = content + internalData.ogImageWidth = content } matchers["meta/og:image:height"] = func(internalData *InternalData, content string, extra string) { - internalData.og_image_height = content + internalData.ogImageHeight = content } matchers["meta/og:audio"] = func(internalData *InternalData, content string, extra string) { - internalData.og_audio = content + internalData.ogAudio = content } matchers["meta/og:audio:url"] = func(internalData *InternalData, content string, extra string) { - internalData.og_audio_url = content + internalData.ogAudioUrl = content } matchers["meta/og:audio:secure_url"] = func(internalData *InternalData, content string, extra string) { - internalData.og_audio_secure_url = content + internalData.ogAudioSecureUrl = content } matchers["meta/og:audio:type"] = func(internalData *InternalData, content string, extra string) { - internalData.og_audio_type = content + internalData.ogAudioType = content } matchers["meta/og:site_name"] = func(internalData *InternalData, content string, extra string) { - internalData.og_site_name = content + internalData.ogSiteName = content } matchers["meta/article:author"] = func(internalData *InternalData, content string, extra string) { - internalData.article_author = content + internalData.articleAuthor = content + } + matchers["meta/article:publisher"] = func(internalData *InternalData, content string, extra string) { + internalData.articlePublisher = content } matchers["meta/article:published_time"] = func(internalData *InternalData, content string, extra string) { - internalData.article_published_time = content + internalData.articlePublishedTime = content + } + + matchers["meta/soundcloud:user"] = func(internalData *InternalData, content string, extra string) { + internalData.soundcloudUser = content + } + matchers["meta/soundcloud:play_count"] = func(internalData *InternalData, content string, extra string) { + internalData.soundcloudPlayCount = content + } + matchers["meta/soundcloud:download_count"] = func(internalData *InternalData, content string, extra string) { + internalData.soundcloudDownloadCount = content + } + matchers["meta/soundcloud:comments_count"] = func(internalData *InternalData, content string, extra string) { + internalData.soundcloudCommentsCount = content + } + matchers["meta/soundcloud:like_count"] = func(internalData *InternalData, content string, extra string) { + internalData.soundcloudLikeCount = content + } + matchers["meta/soundcloud:sound_count"] = func(internalData *InternalData, content string, extra string) { + internalData.soundcloudSoundCount = content + } + matchers["meta/soundcloud:follower_count"] = func(internalData *InternalData, content string, extra string) { + internalData.soundcloudFollowerCount = content } matchers["meta/title"] = func(internalData *InternalData, content string, extra string) { - internalData.meta_title = content + internalData.metaTitle = content } matchers["meta/description"] = func(internalData *InternalData, content string, extra string) { - internalData.meta_description = content + internalData.metaDescription = content } matchers["meta/author"] = func(internalData *InternalData, content string, extra string) { - internalData.meta_author = content + internalData.metaAuthor = content } matchers["meta/theme-color"] = func(internalData *InternalData, content string, extra string) { - internalData.meta_theme_color = content + internalData.metaThemeColor = content } matchers["link/icon"] = func(internalData *InternalData, content string, extra string) { - internalData.link_favicon = content + internalData.linkFavicon = content } matchers["link/author"] = func(internalData *InternalData, content string, extra string) { - internalData.link_author = content + internalData.linkAuthor = content } matchers["link/alternate"] = func(internalData *InternalData, content string, extra string) { if extra == "application/json+oembed" { - internalData.oembed_url = content + internalData.oembedUrl = content } } matchers["title"] = func(internalData *InternalData, content string, extra string) { internalData.title = content } - loadData := func(url string) (Data, error) { - fmt.Printf("Searching for %s\n", url) + providerMatchers := map[string]func(*InternalData, string, string){} + + providerMatchers["meta/og:site_name"] = func(internalData *InternalData, content string, extra string) { + internalData.urlProviderOgSiteName = content + } + providerMatchers["meta/title"] = func(internalData *InternalData, content string, extra string) { + internalData.urlProviderMetaTitle = content + } + providerMatchers["meta/theme-color"] = func(internalData *InternalData, content string, extra string) { + internalData.urlProviderMetaThemeColor = content + } + providerMatchers["link/icon"] = func(internalData *InternalData, content string, extra string) { + internalData.urlProviderLinkFavicon = content + } + providerMatchers["title"] = func(internalData *InternalData, content string, extra string) { + internalData.urlProviderTitle = content + } + + loadData := func(requestedUrl string) (Data, error) { + fmt.Printf("Searching for %s\n", requestedUrl) var data Data - resp, err := client.Get(url) + resp, err := client.Get(requestedUrl) if err != nil { return data, err } - internalData := InternalData{ - url: url, - } + base, _ := url.ParseRequestURI(requestedUrl) - var parseNode func(*html.Node) - parseNode = func(n *html.Node) { - if n.Type == html.ElementNode && n.Data == "meta" { + var parseNode func(map[string]func(*InternalData, string, string), *InternalData, *html.Node) + parseNode = func(matchers map[string]func(*InternalData, string, string), internalData *InternalData, n *html.Node) { + if n.Type == html.ElementNode { attrs := map[string]string{} for _, attr := range n.Attr { attrs[attr.Key] = attr.Val } - name := coalesce([]string{attrs["name"], attrs["property"]}) - if name != "" { - matcher := matchers["meta/"+name] - if matcher != nil { - matcher(&internalData, attrs["content"], "") + if n.Data == "meta" { + name := coalesce([]string{attrs["name"], attrs["property"]}) + if name != "" { + matcher := matchers["meta/"+name] + if matcher != nil { + matcher(internalData, attrs["content"], "") + } } } - } - if n.Type == html.ElementNode && n.Data == "link" { - attrs := map[string]string{} - for _, attr := range n.Attr { - attrs[attr.Key] = attr.Val - } - names := strings.Split(attrs["rel"], " ") - for _, name := range names { - matcher := matchers["link/"+name] - if matcher != nil { - matcher(&internalData, attrs["href"], attrs["type"]) + if n.Data == "link" { + names := strings.Split(attrs["rel"], " ") + for _, name := range names { + matcher := matchers["link/"+name] + if matcher != nil { + matcher(internalData, attrs["href"], attrs["type"]) + } } } - } - if n.Type == html.ElementNode && n.Data == "title" { - c := n.FirstChild - if c != nil && c.Type == html.TextNode { - matcher := matchers["title"] - if matcher != nil { - matcher(&internalData, c.Data, "") + if n.Data == "title" { + c := n.FirstChild + if c != nil && c.Type == html.TextNode { + matcher := matchers["title"] + if matcher != nil { + matcher(internalData, c.Data, "") + } } } } for c := n.FirstChild; c != nil; c = c.NextSibling { - parseNode(c) + parseNode(matchers, internalData, c) } } + internalData := InternalData{ + url: base, + } + contentType := strings.SplitN(resp.Header.Get("Content-Type"), ";", 2)[0] if contentType == "text/html" || contentType == "application/xhtml+xml" || contentType == "application/xhtml" || contentType == "application/xml" { doc, _ := html.Parse(resp.Body) - parseNode(doc) + parseNode(matchers, &internalData, doc) err = resp.Body.Close() if err != nil { panic(err) } + } else if strings.HasPrefix(contentType, "image/") { + internalData.rawType = "image" + } else if strings.HasPrefix(contentType, "video/") { + internalData.rawType = "video" + } else if strings.HasPrefix(contentType, "audio/") { + internalData.rawType = "audio" } var oEmbedData OEmbed - if internalData.oembed_url != "" { - fmt.Printf("Searching for %s\n", internalData.oembed_url) - resp, err := client.Get(internalData.oembed_url) + if internalData.oembedUrl != "" { + fmt.Printf("Searching for %s\n", internalData.oembedUrl) + resp, err := client.Get(internalData.oembedUrl) if err == nil { err = json.NewDecoder(resp.Body).Decode(&oEmbedData) + } else { + fmt.Println(err.Error()) + } + err = resp.Body.Close() + if err != nil { + fmt.Println(err.Error()) + } + } + + siteExists := func(siteUrl string) bool { + resp, err := client.Get(siteUrl) + if err == nil && resp.StatusCode == 200 { + return true + } else { + return false + } + } + + providerFallback1 := func(internalData *InternalData) { + providerUrl := resolve(internalData.url, "/") + fmt.Printf("Searching for %s\n", providerUrl) + providerResp, err := client.Get(providerUrl) + if err == nil { + contentType := strings.SplitN(providerResp.Header.Get("Content-Type"), ";", 2)[0] + if contentType == "text/html" || + contentType == "application/xhtml+xml" || + contentType == "application/xhtml" || + contentType == "application/xml" { + doc, _ := html.Parse(providerResp.Body) + parseNode(providerMatchers, internalData, doc) + err = providerResp.Body.Close() + if err != nil { + panic(err) + } + } + } + } + + providerFallback2 := func(internalData *InternalData) { + providerFaviconUrl := resolve(internalData.url, "/favicon.png") + fmt.Printf("Searching for %s\n", providerFaviconUrl) + if siteExists(providerFaviconUrl) { + internalData.urlProviderIconPng = providerFaviconUrl + } + } + + providerFallback3 := func(internalData *InternalData) { + providerFaviconUrl := resolve(internalData.url, "/favicon.ico") + fmt.Printf("Searching for %s\n", providerFaviconUrl) + if siteExists(providerFaviconUrl) { + internalData.urlProviderIconIco = providerFaviconUrl } - resp.Body.Close() } - data = buildData(internalData, oEmbedData) + data = buildData(internalData, oEmbedData, []func(*InternalData){providerFallback1, providerFallback2, providerFallback3}) return data, err } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - url := strings.TrimSpace(r.URL.Query().Get("url")) - if url != "" { - data, err := loadData(url) + requestedUrl := strings.TrimSpace(r.URL.Query().Get("url")) + if requestedUrl != "" { + data, err := loadData(requestedUrl) if err != nil { - panic(err.Error()) + fmt.Println(err.Error()) + return } + err = returnJson(w, data) if err != nil { - panic(err) + fmt.Println(err.Error()) + return } } }) @@ -503,11 +686,4 @@ func main() { if err != nil { panic(err) } - /* - - loadData("https://medium.com/slack-developer-blog/everything-you-ever-wanted-to-know-about-unfurling-but-were-afraid-to-ask-or-how-to-make-your-e64b4bb9254") - loadData("http://harvard.edu") - loadData("https://twitter.com/dw_politik/status/1092872739445104640") - loadData("https://twitter.com/raketenlurch/status/1093991675209416704") - */ }