Konboi Note

Hugo で URLをカード形式で表示するcustom short code を作った

· Konboi

これもやっていることは二番煎じだけど、記録として残しておく。

はじめに

はてなブログURLをカード形式に整形して表示してくれる機能があるが、hugoにはそれがない。(と記憶している

以前は Iframary というサービスを使って埋め込んでいた

Embeds codes for today
Iframely gives you simple APIs to have all the Web
Iframely · iframely.com
Embeds codes for today

ただ、都度作成すのが面倒だったり、Iframary でリダイレクトさせるのも微妙だなと思っていた。そんな折に hugo に resources.GetRemote と言う HTTP Request 的なことができるメソッド追加されているのを発見した。

resources.GetRemote
Returns a remote resource from the given URL, or nil if none found.
gohugo.io
resources.GetRemote

また、他の人もこの機能を使ってカード形式でURLを埋め込むカスタムコードを作っている人がいたので、自分が使っている hugo layout - paper にあったカスタムコードを作ってみた

コード

カスタムショートコードのコードは以下。

これを layouts/shortcodes/card.html において

{{ <card "URL" > }}

と言う形で使っている

{{- $url := .Get 0 -}}
{{- $title := "" -}}
{{- $description := "" -}}
{{- $image := "" -}}
{{- $siteName := "" -}}

{{- $result := try (resources.GetRemote $url) -}}
{{- if $result.Err -}}
  {{- warnf "Unable to fetch %s: %s" $url $result.Err -}}
{{- else -}}
  {{- with $result.Value -}}
    {{- $html := .Content -}}
    {{/* og:title */}}
    {{- $ogTitle := findRE `<meta[^>]*property=["']og:title["'][^>]*content=["']([^"']+)["'][^>]*>` $html 1 -}}
    {{- if not $ogTitle -}}
      {{- $ogTitle = findRE `<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:title["'][^>]*>` $html 1 -}}
    {{- end -}}
    {{- with $ogTitle -}}
      {{- $title = index . 0 | replaceRE `.*content=["']([^"']+)["'].*` "$1" -}}
    {{- end -}}
    {{/* og:description */}}
    {{- $ogDesc := findRE `<meta[^>]*property=["']og:description["'][^>]*content=["']([^"']+)["'][^>]*>` $html 1 -}}
    {{- if not $ogDesc -}}
      {{- $ogDesc = findRE `<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:description["'][^>]*>` $html 1 -}}
    {{- end -}}
    {{- with $ogDesc -}}
      {{- $description = index . 0 | replaceRE `.*content=["']([^"']+)["'].*` "$1" -}}
    {{- end -}}
    {{/* og:image */}}
    {{- $ogImage := findRE `<meta[^>]*property=["']og:image["'][^>]*content=["']([^"']+)["'][^>]*>` $html 1 -}}
    {{- if not $ogImage -}}
      {{- $ogImage = findRE `<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:image["'][^>]*>` $html 1 -}}
    {{- end -}}
    {{- with $ogImage -}}
      {{- $image = index . 0 | replaceRE `.*content=["']([^"']+)["'].*` "$1" -}}
    {{- end -}}
    {{/* og:site_name */}}
    {{- $ogSite := findRE `<meta[^>]*property=["']og:site_name["'][^>]*content=["']([^"']+)["'][^>]*>` $html 1 -}}
    {{- if not $ogSite -}}
      {{- $ogSite = findRE `<meta[^>]*content=["']([^"']+)["'][^>]*property=["']og:site_name["'][^>]*>` $html 1 -}}
    {{- end -}}
    {{- with $ogSite -}}
      {{- $siteName = index . 0 | replaceRE `.*content=["']([^"']+)["'].*` "$1" -}}
    {{- end -}}
    {{/* fallback: <title> */}}
    {{- if not $title -}}
      {{- $htmlTitle := findRE `<title[^>]*>([^<]+)</title>` $html 1 -}}
      {{- with $htmlTitle -}}
        {{- $title = index . 0 | replaceRE `<title[^>]*>([^<]+)</title>` "$1" -}}
      {{- end -}}
    {{- end -}}
    {{/* fallback: meta description */}}
    {{- if not $description -}}
      {{- $metaDesc := findRE `<meta[^>]*name=["']description["'][^>]*content=["']([^"']+)["'][^>]*>` $html 1 -}}
      {{- if not $metaDesc -}}
        {{- $metaDesc = findRE `<meta[^>]*content=["']([^"']+)["'][^>]*name=["']description["'][^>]*>` $html 1 -}}
      {{- end -}}
      {{- with $metaDesc -}}
        {{- $description = index . 0 | replaceRE `.*content=["']([^"']+)["'].*` "$1" -}}
      {{- end -}}
    {{- end -}}
  {{- end -}}
{{- end -}}

{{- $domain := $url | replaceRE `^https?://([^/]+).*` "$1" -}}
{{- if not $title -}}
  {{- $title = $domain -}}
{{- end -}}

<a href="{{ $url }}" target="_blank" rel="noopener noreferrer" class="paper-card not-prose">
  <div class="paper-card__body">
    <div class="paper-card__title">{{ $title | htmlUnescape }}</div>
    {{- if $description }}
    <div class="paper-card__desc">{{ $description | htmlUnescape }}</div>
    {{- end }}
    <div class="paper-card__meta">{{ if $siteName }}{{ $siteName }} · {{ end }}{{ $domain }}</div>
  </div>
  {{- if $image }}
  <div class="paper-card__thumb">
    <img src="{{ $image }}" alt="{{ $title }}" loading="lazy" />
  </div>
  {{- end }}
</a>

Designは css/style.css を 使っている テーマが読み込む設定なので追加のスタイルをあてるようにしている。

おわりに

OGP 画像の表示部分がいい感じに表示できない時があるが、概ね満足。
もう少し使ってみて問題なさそうなら、既存の記事で Iframely を使っているところがあれば置き換えていく。