Asciinema Shortcode in Hugo

TL;DR

코드를 gist에 따로 올려두었습니다.

Asciinema

Asciinema는 터미널 화면에 대한 영상 서비스로 youtube, vimeo 같이 실제 영상을 처리하는 것이 아닌 js를 이용해서 text를 마치 재생하듯 처리해줍니다.

특징으론 영상 서비스지만, 화면에 나타나는 텍스트들을 실시간으로 복사하고 붙여넣기 할 수 있다는 점이 정말 매력적이 도구입니다. 자세한 내용은 예전에 제가 작성한 소개글을 보시면 대략 어떤 서비스인지 이해가실겁니다.

Embedded player

Asciinema는 웹에서 바로 재생할 수 있도록 스크립트 기반의 Embedded Player를 제공합니다.

<script>
  // AsciinemaPlayer.create(src, containerElement, opts);
  // @sysadmin-info Thank you so much for Improve content :D
  AsciinemaPlayer.create('/demo.cast', document.getElementById('demo'));
</script>

Problem in Hugo

Hugo에서는 기본족으로 markdown 문서 내 스크립트 사용을 제한하고 있습니다. 물론 config.yaml에서 설정을 바꾸어주어 스크립트를 사용할 수 있도록 처리 가능하지만, 이는 보안적인 문제로 그리 추천하진 않습니다.

Asciinema in Hugo

그래서 Hugo에서 asciinema player를 사용하기 위해선 shortcode의 도움을 받아야합니다. hugo의 shortcode는 미리 정의된 템플릿을 특정 문법으로 로드하여 사용할 수 있는 기능으로 변수값도 전달할 수 있어서 잘 구성해둔다면 글 작성하는데 높은 편의성을 제공합니다.

(Shortcode에 대해 더 궁금하다면 이 글을 읽어주세요 )

Download asciinema-palyer

릴리즈 페이지에서 다운로드 후 hugo에서 사용하시는 css, js 디렉토리에 넣어주세요.

https://github.com/asciinema/asciinema-player/releases

css

Hugo 페이지에서 css를 로드할 수 있도록 link 태그를 추가합니다.

<link rel="stylesheet" type="text/css" href="{{ .Site.BaseURL }}css/asciinema-player.css" />

특정 글에서만 link 태그를 로드하기 위해선 아래와 같이 if로 처리해주면 더 깔끔해집니다.

{{ if .Params.asciinema }}
  <link rel="stylesheet" type="text/css" href="{{ .Site.BaseURL }}css/asciinema-player.css" />
{{ end }}

js

css와 마찬가지로 js도 로드해줍시다. 동일하게 if 처리해주시는게 깔끔합니다.

{{ if .Params.asciinema }}
  <script src="{{ .Site.BaseURL }}js/asciinema-player.js"></script>
{{ end }}

Shortcode

마지막으로 실제 페이지에 그려질 shortcode를 작성합니다. asciinema 사이트의 /a/ 하위 디렉토리로 cast id가 들어가도록 처리되고 있어서 src가 https://asciinema.org/a/412004 같은 형태로 처리되도록 구성이 필요합니다.

<div id="asciinema-player"></div>
<script>
  AsciinemaPlayer.create("https://asciinema.org/a/{{ with .Get "key" }}{{ . }}{{ end }}.cast", document.getElementById('asciinema-player'), {
    {{ if .Get "autoplay" }}autoplay: {{ .Get "autoplay" }},{{ end }}
    {{ if .Get "preload" }}preload: {{ .Get "preload" }},{{ end }}
    {{ if .Get "loop" }}loop: {{ .Get "loop" }},{{ end }}
    {{ if .Get "idleTimeLimit" }}idleTimeLimit: {{ .Get "idleTimeLimit" }},{{ end }}
    {{ if .Get "poster" }}poster: "{{ .Get "poster" }}",{{ end }}
    {{ if .Get "terminalFontSize" }}terminalFontSize: {{ .Get "terminalFontSize" }},{{ end }}
    {{ if .Get "terminalFontFamily" }}terminalFontFamily: "{{ .Get "terminalFontFamily" }}",{{ end }}
    {{ if .Get "terminalLineHeight" }}terminalLineHeight: {{ .Get "terminalLineHeight" }},{{ end }}
    {{ if .Get "theme" }}theme: "{{ .Get "theme" }}",{{ end }}
    {{ if .Get "title" }}title: "{{ .Get "title" }}",{{ end }}
    startAt: {{ if .Get "startAt" }}{{ .Get "startAt" }}{{ else }}0{{ end }},
    speed: {{ if .Get "speed" }}{{ .Get "speed" }}{{ else }}1{{ end }},
    cols: {{ if .Get "cols" }}{{ .Get "cols" }}{{ else }}640{{ end }},
    rows: {{ if .Get "rows" }}{{ .Get "rows" }}{{ else }}10{{ end }}
  });
</script>

GoGo!

페이지 본문에 삽입한 asciinema 주소는 https://asciinema.org/a/412004 입니다.

{{ < asciinema key="412004" rows="10" preload="1" >}}

hugo의 template 처리로 {{ 다음에 일부러 공백 넣은 상태입니다. 실제론 붙여야 동작합니다.

hugo 빌드 후 접근해보면 잘 로드되는 것을 확인할 수 있습니다.

References