【Movable Type】記事投稿画面に国会図書館API経由で書籍情報を入力する
概要
国立国会図書館(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