📚

【Movable Type】記事投稿画面に国会図書館API経由で書籍情報を入力する

2024/12/18に公開

概要

国立国会図書館(NDL)が提供しているAPIを利用して、MTの記事投稿画面に書籍情報を入力するコードです。
APIの取得および投稿画面への反映は、MTAppjQueryを利用して実装しています。

APIはNDLが提供している以下のものを利用します。

以下は実際に筆者が使用しているものです。ISBNコードを入力して「取得」ボタンを押下すると、API経由で書籍情報を取得してフィールドに挿入します。
カバー画像が存在する場合は、プレビュー表示させるようにしています。「URL」の項目は、版元ドットコムの該当書籍ページのURLを入れています。

投稿画面

カスタムフィールドを作成する

APIで取得した値を入れるためのカスタムフィールドを作成します。書籍名は記事の「タイトル」欄に挿入します。
以下、作成するカスタムフィールドはすべて「テキストフィールド」で、括弧内はベースネームおよびテンプレートタグです。

  • ISBNコード(article_isbn)
  • 著者名(article_author)
  • 出版社(article_publisher)
  • カバー画像URL(article_cover)
  • URL(article_url)

コード

user.css

カスタムフィールドで追加した「ISBNコード」項目にボタン(.btn_isbn)を追加した際の見た目と、プレビュー用のカバー画像(.cover_view)を表示した際の見た目の調整をしています。

MT7 スタイルガイドを参考に調整すると綺麗です。

#customfield_article_isbn-field .mt-draggable__content {
  display: flex;
  flex-wrap: wrap;
}

#customfield_article_isbn-field #customfield_article_isbn {
  margin-right: auto;
  width: 70%;
}

#customfield_article_isbn-field .btn_isbn {
  width: 25%;
}

#customfield_article_isbn-field .cover_view {
  width: 100%;
}

#customfield_article_isbn-field .cover_view.view {
  margin-top: 1.5rem;
}

user.js

コードはjQueryで書いています。
本記事の最後に実際のコードを掲載しているので、不要であればこの項目は読み飛ばしてください。


ISBNコードを入力して書籍情報を取得するためのボタン(.btn_isbn)と、カバー画像表示用のdiv要素(.cover_view)を、「ISBNコード」(#customfield_article_isbn-field)の項目に追加します。.mt-draggable__contentはフォーム要素を囲っているdiv要素です。

//ISBNコード取得ボタン追加
$('#customfield_article_isbn-field .mt-draggable__content').append('<button type="button" id="getBookData" class="btn_isbn btn btn-primary">取得</button><div class="cover_view" id="cover_view"></div>');

続いて、取得ボタンを押した際の処理を書いていきます。

//取得ボタン押下で情報取得
$('#getBookData').click(function(e) {
  //ここに書いていく
});

まずは変数。

const site_url = '<$mt:BlogURL$>';
const isbn = $('#customfield_article_isbn').val();
const api_url = `https://ndlsearch.ndl.go.jp/api/sru?operation=searchRetrieve&recordPacking=xml&maximumRecords=1&query=isbn=${isbn}`;
const hn_url = `https://www.hanmoto.com/bd/isbn/${isbn}`;
const cover_api = `https://ndlsearch.ndl.go.jp/thumbnail/${isbn}.jpg`;

データの取得には$.ajaxメソッドを利用します。検索用APIのデータ取得に失敗した場合は、「取得失敗!」とアラートが出るようにします。

  $.ajax(api_url)
  .done(function(data, textStatus, jqXHR) {

    //ここに処理を書く

  }).fail(function(jqXHR) {
    console.log(jqXHR);
    alert('取得失敗!');
  });

書影APIの処理。
書影APIは画像があれば画像jpgデータ返却します。例として、夏目漱石『こころ』(岩波文庫)での返却結果
画像がなければXML形式でエラーが返ってくるので、エラーの場合は代替画像を表示・フィールドに挿入するようにします。

//書影有無で出し分け
const checkIfImageExists = (cover_url) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = cover_url;
    img.onload = () => resolve(cover_url);
    img.onerror = () => reject(cover_url);
  });
};
checkIfImageExists(cover_api)
.then((cover_api) => {
  $('#cover_view').html(`<img src="${cover_api}" alt="プレビュー画像">`);
  $('#customfield_article_cover').val(cover_api);
})
.catch((cover_api) => {
  $('#cover_view').html(`<img src="${site_url}lib/images/noimage.png" alt="no image">`);
  $('#customfield_article_cover').val(`${site_url}lib/images/noimage.png`);
});

書籍情報の処理。
検索用APIはXML形式で返却されます。例として、夏目漱石『こころ』(岩波文庫)での返却結果

//書籍情報取得
$('#customfield_article_url').val(hn_url);
$(data).find('recordData').each(function() {
  const dataElement = $(this);
  $('#title').val(dataElement.find('dc\\:title').text());
  $('#customfield_article_author').val(dataElement.find('dc\\:creator').text());
  $('#customfield_article_publisher').val(dataElement.find('dc\\:publisher').text());
});

user.jsコード全体

以下、筆者の環境で実際に動いているコードです。本文エディタは使用していないため、非表示にしています。

(function($) {

//エディタ非表示
mtapp.customize({
  basename: 'body',
  showParent: 'hide'
});

//ISBNコード取得ボタン追加
$('#customfield_article_isbn-field .mt-draggable__content').append('<button type="button" id="getBookData" class="btn_isbn btn btn-primary">取得</button><div class="cover_view" id="cover_view"></div>');

//取得ボタン押下で情報取得
$('#getBookData').click(function(e) {

  //e.preventDefault();
  const site_url = '<$mt:BlogURL$>';
  const isbn = $('#customfield_article_isbn').val();
  const api_url = `https://ndlsearch.ndl.go.jp/api/sru?operation=searchRetrieve&recordPacking=xml&maximumRecords=1&query=isbn=${isbn}`;
  const hn_url = `https://www.hanmoto.com/bd/isbn/${isbn}`;
  const cover_api = `https://ndlsearch.ndl.go.jp/thumbnail/${isbn}.jpg`;

  //取得
  $.ajax(api_url)
  .done(function(data, textStatus, jqXHR) {
    //書影有無で出し分け
    const checkIfImageExists = (cover_url) => {
      return new Promise((resolve, reject) => {
        const img = new Image();
        img.src = cover_url;
        img.onload = () => resolve(cover_url);
        img.onerror = () => reject(cover_url);
      });
    };
    checkIfImageExists(cover_api)
    .then((cover_api) => {
      $('#cover_view').html(`<img src="${cover_api}" alt="プレビュー画像">`);
      $('#customfield_article_cover').val(cover_api);
    })
    .catch((cover_api) => {
      $('#cover_view').html(`<img src="${site_url}lib/images/noimage.png" alt="no image">`);
      $('#customfield_article_cover').val(`${site_url}lib/images/noimage.png`);
    });

    //書籍情報取得
    $('#customfield_article_url').val(hn_url);
    $(data).find('recordData').each(function() {
      const dataElement = $(this);
      $('#title').val(dataElement.find('dc\\:title').text());
      $('#customfield_article_author').val(dataElement.find('dc\\:creator').text());
      $('#customfield_article_publisher').val(dataElement.find('dc\\:publisher').text());
    });
  }).fail(function(jqXHR) {
    console.log(jqXHR);
    alert('取得失敗!');
  });

});

})(jQuery);

以上です。

Discussion