From a84325841005053b65483bd33d273b9ebca22d6d Mon Sep 17 00:00:00 2001 From: Brandur Date: Fri, 24 Nov 2017 19:46:36 +0900 Subject: [PATCH] Detect image locations for hook/Twitter card Detects image locations and generates URLs automatically for hook and Twitter card images. This carries the advantage of (1) less boilerplate in YAML frontmatter (all of which has been removed), and (2) allows us to support multiple formats (I want to have PNG card and hook images). Former-commit-id: c5efb5e9e3028d99d6e0289e6da56aa98dc4a252 --- cmd/sorg-build/main.go | 60 +++++++++++++------ content/articles/acid.md | 2 - content/articles/api-paradigms.md | 2 - content/articles/breaktime.md | 1 - content/articles/heroku-values.md | 2 - content/articles/idempotency-keys.md | 2 - content/articles/interfaces.md | 2 - content/articles/minimalism.md | 2 - content/articles/newsletters.md | 2 - content/articles/page.md | 2 - content/articles/postgres-atomicity.md | 2 - content/articles/postgres-reads.md | 2 - content/articles/redis-streams.md | 2 - content/articles/stripe-running.md | 1 - content/articles/webhooks.md | 2 - content/articles/x100s-hack.md | 2 - .../drafts/microservices-and-the-monolith.md | 2 - content/drafts/ruby-scale.md | 2 - content/fragments/airpods.md | 1 - content/fragments/ipad-mini.md | 1 - content/fragments/ivy.md | 1 - content/fragments/monkeybrains.md | 1 - content/fragments/sprawl-blues.md | 1 - content/fragments/wgt-2015.md | 1 - content/fragments/your-name.md | 1 - views/articles/index.ace | 4 +- 26 files changed, 45 insertions(+), 58 deletions(-) diff --git a/cmd/sorg-build/main.go b/cmd/sorg-build/main.go index 84e5edb11..e6e4c364d 100644 --- a/cmd/sorg-build/main.go +++ b/cmd/sorg-build/main.go @@ -57,9 +57,9 @@ type Article struct { // Hook is a leading sentence or two to succinctly introduce the article. Hook string `yaml:"hook"` - // HookImage is a boolean indicating whether there's a preview image for - // the article that can be shown on the index page. - HookImage bool `yaml:"hook_image"` + // HookImageURL is the URL for a hook image for the article (to be shown on + // the article index) if one was found. + HookImageURL string `yaml:"-"` // Image is an optional image that may be included with an article. Image string `yaml:"image"` @@ -81,10 +81,6 @@ type Article struct { // included as YAML frontmatter, but rather calculated from the article's // content, rendered, and then added separately. TOC string `yaml:"-"` - - // TwitterImage is a boolean indicating whether there's an image for - // the article that can be shown in a Twitter card. - TwitterImage bool `yaml:"twitter_image"` } // PublishingInfo produces a brief spiel about publication which is intended to @@ -193,10 +189,6 @@ type Fragment struct { // Title is the fragment's title. Title string `yaml:"title"` - - // TwitterImage is a boolean indicating whether there's an image for - // the article that can be shown in a Twitter card. - TwitterImage bool `yaml:"twitter_image"` } // PublishingInfo produces a brief spiel about publication which is intended to @@ -583,12 +575,26 @@ func compileArticle(dir, name string, draft bool) (*Article, error) { return nil, err } + format, ok := pathAsImage( + path.Join(sorg.ContentDir, "images", article.Slug, "hook"), + ) + if ok { + article.HookImageURL = "/assets/" + article.Slug + "/hook." + format + } + + if err != nil && !os.IsNotExist(err) { + return nil, err + } + card := &twitterCard{ Title: article.Title, Description: article.Hook, } - if article.TwitterImage { - card.ImageURL = sorg.AbsoluteURL + "/assets/" + article.Slug + "/twitter@2x.jpg" + format, ok = pathAsImage( + path.Join(sorg.ContentDir, "images", article.Slug, "twitter@2x"), + ) + if ok { + card.ImageURL = sorg.AbsoluteURL + "/assets/" + article.Slug + "/twitter@2x." + format } locals := getLocals(article.Title, map[string]interface{}{ @@ -710,14 +716,15 @@ func compileFragment(dir, name string, draft bool) (*Fragment, error) { // A lot of fragments still have unwritten hooks, so only add a card where // a fragment has a configured Twitter image for the time being. var card *twitterCard - if fragment.TwitterImage { + format, ok := pathAsImage( + path.Join(sorg.ContentDir, "fragments", fragment.Slug, "twitter@2x"), + ) + if ok { card = &twitterCard{ + ImageURL: "/assets/fragments/" + fragment.Slug + "/twitter@2x." + format, Title: fragment.Title, Description: fragment.Hook, } - if fragment.TwitterImage { - card.ImageURL = sorg.AbsoluteURL + "/assets/fragments/" + fragment.Slug + "/twitter@2x.jpg" - } } locals := getLocals(fragment.Title, map[string]interface{}{ @@ -2113,6 +2120,25 @@ create: return os.Symlink(source, dest) } +// Checks if the path exists as a common image format (.jpg or .png only). If +// so, returns the discovered extension (e.g. "jpg") and boolean true. +// Otherwise returns an empty string and boolean false. +func pathAsImage(extensionlessPath string) (string, bool) { + // extensions must be lowercased + formats := []string{"jpg", "png"} + + for _, format := range formats { + _, err := os.Stat(extensionlessPath + "." + format) + if err != nil { + continue + } + + return format, true + } + + return "", false +} + func renderView(layout, view, target string, locals map[string]interface{}) error { log.Debugf("Rendering: %v", target) diff --git a/content/articles/acid.md b/content/articles/acid.md index 06151484c..eacbe5744 100644 --- a/content/articles/acid.md +++ b/content/articles/acid.md @@ -6,8 +6,6 @@ hook: On ensuring system integrity, operability, and correctness through a solid foundational database, and how ACID transactions and strong constraints work in your favor. Why to prefer Postgres over MongoDB. -hook_image: true -twitter_image: true --- In 1983, Andreas Reuter and Theo Härder coined the acronym diff --git a/content/articles/api-paradigms.md b/content/articles/api-paradigms.md index 4b8e7ecb4..7be31f033 100644 --- a/content/articles/api-paradigms.md +++ b/content/articles/api-paradigms.md @@ -5,8 +5,6 @@ location: San Francisco hook: Musings on the next API technology, and whether REST-ish JSON over HTTP is just "good enough" to never be displaced in a significant way. -hook_image: true -twitter_image: true hn_link: https://news.ycombinator.com/item?id=14003134 --- diff --git a/content/articles/breaktime.md b/content/articles/breaktime.md index 9603e8ef1..f61c3d97c 100644 --- a/content/articles/breaktime.md +++ b/content/articles/breaktime.md @@ -4,7 +4,6 @@ published_at: 2014-02-02T18:15:28Z location: San Francisco hook: In search of an alternative to BreakTime. The discovery of a very classical solution. -hook_image: true --- A few years ago I took the plunge and started using diff --git a/content/articles/heroku-values.md b/content/articles/heroku-values.md index ff595480f..7dc5623b5 100644 --- a/content/articles/heroku-values.md +++ b/content/articles/heroku-values.md @@ -4,8 +4,6 @@ image: "/assets/heroku-values/heroku-values.jpg" location: San Francisco published_at: 2015-11-05T06:20:16Z title: My Heroku Values -hook_image: true -twitter_image: true hn_link: https://news.ycombinator.com/item?id=14286143 --- diff --git a/content/articles/idempotency-keys.md b/content/articles/idempotency-keys.md index 8ea9fb73a..63a36e269 100644 --- a/content/articles/idempotency-keys.md +++ b/content/articles/idempotency-keys.md @@ -6,8 +6,6 @@ hook: Building resilient services by identifying foreign state mutations and grouping local changes into restartable atomic phases so that every request can be driven to completion. -hook_image: true -twitter_image: true hn_link: https://news.ycombinator.com/item?id=15569478 --- diff --git a/content/articles/interfaces.md b/content/articles/interfaces.md index f1d90a256..9add4cc9d 100644 --- a/content/articles/interfaces.md +++ b/content/articles/interfaces.md @@ -5,8 +5,6 @@ location: San Francisco hook: How we overvalue the wrong technology and novel aspects of interface design at the expense of substantial gains to our productivity. -hook_image: true -twitter_image: true hn_link: https://news.ycombinator.com/item?id=13733777 --- diff --git a/content/articles/minimalism.md b/content/articles/minimalism.md index ebca3937b..a0dd573ba 100644 --- a/content/articles/minimalism.md +++ b/content/articles/minimalism.md @@ -5,8 +5,6 @@ location: San Francisco hook: Practicing minimalism with the lofty goal of total ephemeralization to build coherent, stable, and operable stacks. -hook_image: true -twitter_image: true attributions: Photographs by Ben Harrington (SR-71), Robyn Jay (embers of a burning fire), and Md. Al Amin (boat and sky). Licensed under Creative Commons BY-NC-ND 2.0, BY-SA 2.0, and CC BY 2.0 respectively. --- diff --git a/content/articles/newsletters.md b/content/articles/newsletters.md index 0c488d3f1..61d26054f 100644 --- a/content/articles/newsletters.md +++ b/content/articles/newsletters.md @@ -3,8 +3,6 @@ title: "Pseudo-HTML and Pidgin CSS: Building an Email Newsletter" published_at: 2017-08-02T14:52:31Z hook: Building a toolchain for sending a newsletter, and the dismal state of HTML and CSS in email. -hook_image: true -twitter_image: true --- After a recent trip to Portland, I decided to try writing a diff --git a/content/articles/page.md b/content/articles/page.md index ec6a439c8..d9ec134c9 100644 --- a/content/articles/page.md +++ b/content/articles/page.md @@ -3,8 +3,6 @@ hook: How the page almost transitioned successfully to the digital world, but is in decline in new media. The lessons that we can learn from this age-old design element, and why we should hope for its re-emergence. -hook_image: true -twitter_image: true image: "/assets/page/page.jpg" location: San Francisco published_at: 2014-01-26T18:56:46Z diff --git a/content/articles/postgres-atomicity.md b/content/articles/postgres-atomicity.md index a7cfe356a..0a5fadd8d 100644 --- a/content/articles/postgres-atomicity.md +++ b/content/articles/postgres-atomicity.md @@ -5,8 +5,6 @@ location: San Francisco hook: A dive into the mechanics that allow Postgres to provide strong atomic guarantees despite the chaotic entropy of production. -hook_image: true -twitter_image: true hn_link: https://news.ycombinator.com/item?id=15027870 --- diff --git a/content/articles/postgres-reads.md b/content/articles/postgres-reads.md index 6df94eb2b..44bea2175 100644 --- a/content/articles/postgres-reads.md +++ b/content/articles/postgres-reads.md @@ -6,8 +6,6 @@ published_at: 2017-11-17T22:02:56Z hook: Scaling out operation with read replicas and avoiding the downside of stale reads by observing replication progress. -hook_image: true -twitter_image: true hn_link: https://news.ycombinator.com/item?id=15726376 --- diff --git a/content/articles/redis-streams.md b/content/articles/redis-streams.md index c85759f6b..8a9cdf200 100644 --- a/content/articles/redis-streams.md +++ b/content/articles/redis-streams.md @@ -5,8 +5,6 @@ location: San Francisco hook: Building a log-based architecture that's fast, efficient, and resilient on the new stream data structure in Redis. -hook_image: true -twitter_image: true hn_link: https://news.ycombinator.com/item?id=15653544 --- diff --git a/content/articles/stripe-running.md b/content/articles/stripe-running.md index 3cc43491e..d2502c981 100644 --- a/content/articles/stripe-running.md +++ b/content/articles/stripe-running.md @@ -3,7 +3,6 @@ hook: Crunching running data with prepared statements in Postgres. location: San Francisco published_at: 2015-10-24T20:55:32Z title: Running at Stripe -hook_image: true --- One pleasant surprise of Stripe's internal culture was the existence of a diff --git a/content/articles/webhooks.md b/content/articles/webhooks.md index e98bbeceb..75054ea6a 100644 --- a/content/articles/webhooks.md +++ b/content/articles/webhooks.md @@ -6,8 +6,6 @@ hook: When it comes to streaming APIs, there's now a lot of great options like SSE, GraphQL subscriptions, and GRPC streams. Let's examine whether webhooks are still a good choice in 2017. -hook_image: true -twitter_image: true attributions: Thanks to Spencer Dixon for review. diff --git a/content/articles/x100s-hack.md b/content/articles/x100s-hack.md index f45f30535..a80f3c156 100644 --- a/content/articles/x100s-hack.md +++ b/content/articles/x100s-hack.md @@ -4,8 +4,6 @@ hook: If you find that the price tag for a Fuji-official adapter ring for the X1 location: San Francisco published_at: 2014-08-03T16:50:19Z title: A Cheap X100S Filter Ring Hack -hook_image: true -twitter_image: true --- The [official Fujifilm X100/X100S 49 mm adapter ring](http://www.amazon.com/Fujifilm-AR-X100-Adapter-Ring-49mm/dp/B004MME69S) which allows you to mount extra filters onto your lens will run you about $40, which is a little steep considering that its entire role in life is to act as an expensive spacer. diff --git a/content/drafts/microservices-and-the-monolith.md b/content/drafts/microservices-and-the-monolith.md index c92851169..f7027ff5c 100644 --- a/content/drafts/microservices-and-the-monolith.md +++ b/content/drafts/microservices-and-the-monolith.md @@ -3,8 +3,6 @@ title: Microservices and the Monolith published_at: 2017-01-05T16:41:25Z hook: Microservices may be out of vogue, but we should be wary of overcompensation. -hook_image: true -twitter_image: true --- About three years ago, the idea of a service-oriented diff --git a/content/drafts/ruby-scale.md b/content/drafts/ruby-scale.md index e49f5e12b..1044c42c2 100644 --- a/content/drafts/ruby-scale.md +++ b/content/drafts/ruby-scale.md @@ -4,8 +4,6 @@ published_at: 2017-04-18T14:23:28Z location: San Francisco hook: The challenges of scaling and operating a big Ruby codebase (that are not related to performance). -hook_image: true -twitter_image: true --- Ruby is a beautiful language. Speaking from experience, diff --git a/content/fragments/airpods.md b/content/fragments/airpods.md index 5041de27a..abb1d3b10 100644 --- a/content/fragments/airpods.md +++ b/content/fragments/airpods.md @@ -2,7 +2,6 @@ title: AirPods published_at: 2017-03-29T14:44:33Z image: /assets/fragments/airpods/vista.jpg -twitter_image: true hook: I'm happy to be cheering from the bleachers as Apple makes their first home run in years. --- diff --git a/content/fragments/ipad-mini.md b/content/fragments/ipad-mini.md index 0cb680a16..34379944a 100644 --- a/content/fragments/ipad-mini.md +++ b/content/fragments/ipad-mini.md @@ -2,7 +2,6 @@ title: The iPad Mini published_at: 2016-06-12T22:26:17Z image: /assets/fragments/ipad-mini/vista.jpg -twitter_image: true hook: An ode to one of my favorite Apple devices. --- diff --git a/content/fragments/ivy.md b/content/fragments/ivy.md index e01d72374..8e71d1b3c 100644 --- a/content/fragments/ivy.md +++ b/content/fragments/ivy.md @@ -1,7 +1,6 @@ --- title: Ivy published_at: 2016-08-24T03:12:31Z -twitter_image: true image: /assets/fragments/ivy/vista.jpg hook: Stripe's new home in SOMA. --- diff --git a/content/fragments/monkeybrains.md b/content/fragments/monkeybrains.md index 00ce9b1af..8629db7e0 100644 --- a/content/fragments/monkeybrains.md +++ b/content/fragments/monkeybrains.md @@ -2,7 +2,6 @@ title: MonkeyBrains published_at: 2016-01-23T01:15:58Z image: /assets/fragments/monkeybrains/vista.jpg -twitter_image: true hook: A very brief review of the local San Francisco ISP. --- diff --git a/content/fragments/sprawl-blues.md b/content/fragments/sprawl-blues.md index fdfc04586..3dea6d7e1 100644 --- a/content/fragments/sprawl-blues.md +++ b/content/fragments/sprawl-blues.md @@ -2,7 +2,6 @@ title: The Sprawl Blues published_at: 2016-01-03T22:18:36Z image: /assets/fragments/sprawl-blues/vista.jpg -twitter_image: true hook: On sprawl and commute times in North America. --- diff --git a/content/fragments/wgt-2015.md b/content/fragments/wgt-2015.md index d5f91107f..1a676d74a 100644 --- a/content/fragments/wgt-2015.md +++ b/content/fragments/wgt-2015.md @@ -2,7 +2,6 @@ title: WGT 2015 Abstract published_at: 2015-05-29T13:34:59Z image: /assets/fragments/wgt-2015/vista.jpg -twitter_image: true hook: A whirlwind tour of Wave-Gotik-Treffen 2015. --- diff --git a/content/fragments/your-name.md b/content/fragments/your-name.md index 457fddb2b..d1a3dde20 100644 --- a/content/fragments/your-name.md +++ b/content/fragments/your-name.md @@ -2,7 +2,6 @@ title: Your Name published_at: 2017-04-11T01:26:59Z image: /assets/fragments/your-name/vista.jpg -twitter_image: true hook: A short review of Makoto Shinka's latest animated film. --- diff --git a/views/articles/index.ace b/views/articles/index.ace index 8ba057899..72b465c8a 100644 --- a/views/articles/index.ace +++ b/views/articles/index.ace @@ -25,9 +25,9 @@ ul {{range .Articles}} li - {{if .HookImage}} + {{if .HookImageURL}} a href="/{{.Slug}}" - img src="/assets/{{.Slug}}/hook.jpg" data-rjs="2" + img src="{{.HookImageURL}}" data-rjs="2" {{end}} .title a href="/{{.Slug}}"