『7回目の出直し🌻』

好きなことを自分のペースで、のんびり更新

【後編】はてなブログの記事に最終更新日を表示する:GASのデプロイとJavaScriptでの呼び出し

ブログ記事に最終更新日を出すための その2 f:id:kanaxx43:20210809153157p:plain

はじめに

ブログの記事に更新日を表示しようという企画の第二部です。
この記事は後編です。

前の記事はこちらです。 kanaxx.hatenablog.jp

作ったもの

記事ページに最終更新日を差し込むスクリプトです。最近覚えたGoogle Apps Scriptとスプレッドシートを使って作りました。

1か月以内なら何日前と表示
f:id:kanaxx43:20210809140747p:plain

1か月以上たっている場合は何か月前と表示
f:id:kanaxx43:20210809140750p:plain

1年以上経っている場合は、何年前と表示
f:id:kanaxx43:20210809140749p:plain

これだけです。

作戦会議

GASだけで最終更新日を表示するのは難しいので、二つに分割して考えます。

  1. sitemap_indexとsitemap.xmlから記事のURLと最終更新日を取り出すGASとスプレッドシート
  2. GASをウェブアプリケーション化して、記事の最終更新日を取得するJavaScript

この方法であれば、記事ページを開いたときに1回だけ外部にアクセスするだけで最終更新日がとれます。

後編では、上の2番目の作業を行います。

後編でやること

  • 前回作成したスプレッドシートにウェブアプリケーション用の関数を追加する
  • GASをウェブアプリケーションとして公開をしJavaScriptから呼び出し可能な状態にする
  • はてなブログにJavaScriptを埋め込み、APIを呼び出して更新日を取り出す

3. 外部呼出しの関数を追加

Google Apps Scriptを外部から利用可能(呼び出し可能)にするためのお作法があるので、それに従って実装していきます。

簡単にいうとdoGet関数doPost関数を作成して、デプロイするという手順を踏みます。

Develperガイドも参考に
https://developers.google.com/apps-script/guides/web

doGetの関数を準備

今回はHTTP GETでのアクセスをするので、doGet関数だけ作ります。doPostは不要です。

スクリプトエディタの「ファイル」の隣にある+マークで新しいファイルを作成し、以下のコードをコピペします。ファイル名は何でもよいです。
f:id:kanaxx43:20210809145334p:plain

// parameter url
function doGet(e){
  let url = e.parameter.url;
  console.log('url=%s', url);
  let lastmod;

  if(url == null || (lastmod=getLastMod(url))==null){
    return ContentService.createTextOutput('null');
  }
  
  let now = new Date();
  let diff = now - lastmod; //msec
  let diffDays = Math.floor(diff/1000/60/60/24);
  let diffMonths = Math.floor(diffDays/30);
  let diffYears = Math.floor(diffDays/365);
  
  console.log('%s(msec) | %s(days), %s(month), %s(year)', diff, diffDays, diffMonths, diffYears);

  let fullDate = Utilities.formatDate(lastmod, 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
  let shortDate = Utilities.formatDate(lastmod, 'Asia/Tokyo', 'yyyy-MM-dd');

  let data = {diffYears, diffMonths, diffDays, fullDate, shortDate, url };
  let payload = JSON.stringify(data);
  let output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(payload);

  return output;
}

//for testing
function testDoGet(){
  let param = {
    //parameter:{url : 'https://kanaxx.hatenablog.jp/entry/typec-cable'}
    parameter:{url : 'https://kanaxx.hatenablog.jp/entry/hatenablog/responsive-with-cloudinary'}
  };
  let ans = doGet(param);
  console.log(ans);
}

スクリプトはここにも置いてあります https://github.com/kanaxx/hatenablog-omocha/blob/main/ladtmodifiedtime/doget.gs

やっていることを簡単に
  • doGetを定義します。パラメータとしてurl=xxxを受け取ります。
    • eからURLの値を取り出し、getLastModを呼びます
    • getLastModは、「データ」シートのA列からURLと一致するセルを探し、見つかったときは一つ右のセルの値をとります
    • 上でとった値を日付の形式にフォーマットして返します
  • 最終更新日と現在時間を比較して、日数の差、月数の差、年数の差を計算しておきます
  • 計算した結果をJSON形式で戻します

4.デプロイする

doGetを作ったら、デプロイします。

デプロイとは、作ったスクリプトをインターネット側に公開をして利用できるようにする作業のことです。日本語だと配備と呼ぶことがありますがデプロイでいきます。 スクリプトエディタで書いただけでは外部から使える状態にならないので、デプロイをします。

新規にデプロイする

一回もやったことがない人は新規にデプロイします。デプロイはスプレッドシート(ワークブック)ごとに行うので、別ブックでスクリプトを書いたらそれぞれでデプロイが必要です。

デプロイ画面を開く

スクリプトエディタの右上にあるデプロイボタンを押します。 f:id:kanaxx43:20210809104703p:plain

デプロイ種類が3つ出てきますが、初めての人は「新しいデプロイ」を押します。
f:id:kanaxx43:20210809104709p:plain

デプロイ設定画面

新しいデプロイウィンドウが出てくるので、必要事項を入力します。
f:id:kanaxx43:20210809104906p:plain

といっても特に困るものはなくて

  • 1はわかりやすい説明文を入れる
  • 2は自分
  • 3は全員

になります。「デプロイ」ボタンを押すと完了です。

デプロイ完了画面

新しくデプロイをすると、そのアプリケーション用のURLが発行されます。 f:id:kanaxx43:20210809110018p:plain

このURLが外部からdoGetを呼ぶためのURLです。あとで使うのでメモしておきます。

プログラムを修正したは再デプロイ

一度デプロイしたあとに問題が見つかってプログラムを修正した場合には、もう一度デプロイしないと変更は反映されません。

デプロイ管理画面を開く

まず、「デプロイの管理」を押し デプロイされているアプリケーションの一覧を開きます
f:id:kanaxx43:20210809105645p:plain

デプロイ設定画面

左上のアクティブの中から変更したいものを選び、右側の編集ボタン(鉛筆マーク)を押します。 f:id:kanaxx43:20210809112232p:plain

通常は左上は1つしかないので選択に困ることはないと思います。

再デプロイ実行

編集ボタンを押したら、右側が入力可能になります。一番上にある「バージョン」の選択肢から「最新バージョン」を選び、デプロイボタンを押します。 f:id:kanaxx43:20210809112236p:plain

デプロイ済みの状態で新しくデプロイをすると、呼び出しのURLが新しいものが割り当てられてしまいます。古いほうが使えなくなるわけではないので、慌てず急がすもう一度デプロイしなおせば大丈夫です。

ウェブアプリケーションをテスト

デプロイが完了すると、先ほどのURLをブラウザで叩ける状態になります。試しに実行してみる場合は、このような形式で実行します。 \https://script.google.com/macros/s/xxxxxxx/exec?url=123

最終部分にurl=123の形式でパラメータを指定します。123の部分に存在するURLに変更すれば結果が取れます。

こんな感じでデータが取れます。
f:id:kanaxx43:20210809150432p:plain

5.JavaScriptから呼び出す

やっと最終ステップです。

データを貯めるスプレッドシートができ、 スプレッドシートに自動でデータを持ってくる仕組みができ、 スプレッドシートのデータを外部に返す仕組みができたので、 次は取り出す部分です。

コード

JavaScript側のコードはシンプルです。GASにアクセスしてデータを取り出し、戻ってきた値を少々加工してページ内に埋め込むだけです。
CSSもセットで置いてしまっていますが、デザインCSSエリアに置くのでもいいと思います。

<script>
  //Change here to your own URL
  let lastmodURL = 'https://script.google.com/macros/s/xxx-yyy/exec';

  fetch( lastmodURL + '?url=' + location.href)
  .then(response=>response.json())
  .then(lastmod=>{
    console.log(lastmod);
    if(lastmod !=null && $('div.entry-date').length==1){
      let diffText = '';
      if( lastmod.diffYears > 0 ){ 
        diffText =  ' (' + lastmod.diffYears+'年前)';
      }else if( lastmod.diffMonths > 0 ){ 
        diffText = ' (' + lastmod.diffMonths +'ヵ月前)';
      }else if( lastmod.diffDays > 0) { 
        diffText =   ' (' + lastmod.diffDays +'日前)';
      
      $('div.entry-date').after('<span class="entry-lastmod">更新日:'+lastmod.shortDate + diffText+'</span>');
    }
  });
</script>

<!-- design for lastmod -->
<style>
  span.entry-lastmod{ margin-left:20px; font-size:80%;}
</style>
簡単に説明

fetchメソッドを使って外部URLへ接続します。
jsonデータ(変数:lastmod)が受け取れた場合は、表示する内容をifの3分岐で調整しています。

  • lastmod.diffYearが1以上なら「x年前」
  • lastmod.diffMonthが1以上なら「xヵ月前」
  • lastmod.diffDaysが1以上なら「x日前」

最後に、<span>タグを作成し、日付周辺に適当に押し込みます。(ここでjQuery使っちゃう弱者です)

JavaScriptを設置

今回のスクリプトは記事ページだけが反応すればよいので、記事下エリアに差し込みます。

ブログ管理画面の「デザイン設定」>「カスタマイズ」>「記事」>「記事下」のHTMLエリアに上のコードを貼り付けます。
f:id:kanaxx43:20210809143621p:plain

保存すれば終わりです。

6. 動作確認

適当に記事ページを閲覧するだけです。

公開したGASが呼び出された場合には、GASの実行数のページにリアルタイムに表示されます。
f:id:kanaxx43:20210809151451p:plain

無事、最終更新日が表示できました。

まとめ

Google Apps Scriptをデプロイし、別のアプリケーション(はてなブログ)から呼び出す連携を作ってみました。
GASのトリガーで自動でデータを集めデータベース化し、そのデータを検索可能な形でデプロイするのは意外と応用が効く仕組みだと思います。

とりあえず作りたかっただけなので、自己満足です。

参考にしたサイト

Develperガイド
https://developers.google.com/apps-script/guides/web

GASでJSONを返すAPIを作る
https://qiita.com/tfuruya/items/3c306ee03d1ac290bcef