🐙

Githubのプロフィールを動的に変化させるカスタマイズを作ってみた

2023/03/12に公開

Githubのプロフィール、いろんなトロフィーとかSNSとか入れている方いるじゃないですか。たのしそう!
で、私も真似したいのだけど、Githubの活動は大してしてないし、極度のSNS疲れでTwitterアカウント消滅させたばっかだしで、外部に出すようなものがないわけです。かなしい

外部に出すと言うか、ちょっとしたポートフォリオ?的にこんなことできますの意を込めて、動的に変化させるという点をチャレンジしてみることにした

実際の動作

Readmeのカスタムって中身なにやっているの?って調べたところ、実装方法として

  1. 動的に変化する画像を返してくれるサーバーを立ててしまう
  2. Github Actionを使って更新を定期的にCommitする

の2種類があるみたい
どっちがいいか、美しいかは考える必要があるかもなのだけどひとまず置いておいて、今回は1番目の方法を取ろうかと思う
fly.ioの無料枠余ってるし

大昔に迷路生成プログラムを書いたことあるので、それをホスティングしてみることにする
Github用に色変えたりしたけど、サンプルとしてはこんな画像を出していこうと思う。黒が壁、赤がスタートで緑がゴールなイメージ

サーバー立てた

アクセスすると、画像生成→画像だけを返すという動きをするAPIを作りました

内部の動きとして、

  1. URLから迷路の1辺の情報を取得
  2. 壁伸ばし法で迷路生成
  3. 迷路(2次元配列)をSVG文字列に変換
  4. Header情報でSVG指定、キャッシュ保存させない設定をする
  5. SVGをレスポンスとして返す
  6. GithubのReadmeで描画される

のステップで進みます

1から3までは単純にFlaskでのルーティングとPythonの関数で返す物を作る段階なので割愛
4からはただのWebサイトと違う、APIっぽい動きなので書き記します

画像のみを返すためにヘッダー情報でSVGを指定する

Flaskで画像のみを返したい時、SVG画像をxml、あるいはpng画像ならバイナリ形式(io.byteIOかなにかで変換)に変換して返そうとなるわけですが、その場合

<html><body>
…
</body></html>

までが勝手についてしまうらしい
レスポンスがドキュメントじゃなくって、画像ですよって明示しなければいけないみたいです

サンプルとしてはこんな感じ

from flask import Flask, make_response

@app.route(‘/’)
    svg_str=SVG画像タグの文字列
    response=make_response(svg_str)
    response.headers.set('Content-Type', 'image/svg+xml')
    return response

Flask内のmake_responseを使って、ヘッダーに、これはSVG画像ですよという情報を追加

実際にアクセスするたびに迷路の形が変わっている画像のみが返ってくる。やったね

キャッシュ無効のためのヘッダー情報を設定する

GithubのReadmeは画像が読み込まれると、それをGithub上でキャッシュして保存する動きをするみたい
なので動的に変えるAPIを作っても、そこに保存した画像を参照されたら、意味がないわけです
そこでヘッダー情報にキャッシュを禁止する項目を追加します

    response.headers.set('Cache-Control', 'no-cache')
    response.headers.set('Cache-Control', 'no-store')
    response.headers.set('Cache-Control', 'must-revalidate')
    response.headers.set('Cache-Control', 'max-age=0')
    response.headers.set('Pragma', 'no-cache')

PragmaはHTTP/1.0で、Cache-Controllの方はHTTP/1.1 で使われているらしい。つまりPragmaは古いのでなくってもいいのかも(ここでは念のため付けているけれど)
キャッシュ保存の無効化をしておくと、Github内に保存されなくなって、更新するたびにアクセス(その結果新しい迷路が生成)されるという寸法

さぁGithubのプロフィールに貼ろう

ヘッダーの設定が終わったら実際にFly.ioにデプロイしていきます。Dockerfileをこねくり回すの楽しかったので、その部分はまた別に記事にすると思う

Fly.ioではhttps://設定したAppName.fly.devのURLとして扱えるようになるので、そこからFlaskのRoutingでの設定通りに呼び出してgithubに画像を貼ります

![alt_message](image_url)

のimage_urlをAPIのアドレスに変えるだけなので、まぁ特に書くこと無いですね

結果的にこんな感じで更新するたびに変化するプロフィール画面の完成。ぱちぱちぱちぱちぱち〜


おまけ: 詰みそうになったこと

Flaskでlocalhost外からアクセスする場合、

flask run —host=‘0.0.0.0’

のように、hostを指定する必要があった
ずぅっと“あら?ポートはちゃんと80番のhttpが開いている設定よね??”って、fly.tomlファイルと格闘していました。変に無駄に考えていてしまった
豆腐にかすがい、日曜が崩壊。原因わからず、当時は狼狽(ろうばい)
(まぁ、ポート関連の設定にちょっとだけ詳しくなったからまぁいいっか。そう思うことにして、この記事は散会!)

Discussion