はじめに
NotesクライアントのビューにWebページのようなサムネイル画像を表示したいと思ったことはないでしょうか?イメージリソースに画像を登録し、文書にイメージリソース名を指定すれば、Notesビューにもサムネイル画像を表示することは可能です。
しかし、イメージリソースは設計レベルの要素なので、一般ユーザーが気軽に登録することはできません。今回ノーツコンソーシアム大阪研究会の浜さんがLotusScriptのDXLクラスを拡張し、LotusScriptからイメージリソースの登録と削除を可能にする関数を作られたので、それを活用し、YoutubeAPIからチャンネル動画一覧とサムネイル画像を取得し、Notesビューに表示してみたいと思います。
【完成型】
※実行確認はWindows10 Pro + Notes12.0.2FP1を使用しています。NotesJSONクラスを利用しているためNotes10以降の環境が必要です。
YoutubeAPIから情報を取得するには?
YoutubeAPIから情報を取得するにはどのようにすれば良いでしょう?わからないことはChatGPTに聞いてみます。ここでの注意はまず、できるであろうメジャーな言語で問いかけを作る点です。
「youtube apiを使って、特定チャンネルの動画一覧を取得するJavaScriptを書いて下さい」
と聞いてみると下記のような回答が返ってきます。(回答は毎回異なります。)
上記コードからYoutubeAPIの利用には「API Key」「ChannelID」「問合せURL」が必要なことがわかります。
まずは確実に動くコードが欲しいので、JavaScriptのソースをHTMLファイルなどに書き込み、実行後は「VBAに変換して下さい」と質問し、VBAに書き換えて貰うとLotusScriptに移植しやすくなります。現在の生成AIの活用では、質問→実装テスト→質問→実装テストの繰り返しが必要です。
【APIKeyの取得】
APIKeyはGoogleアカウントを持っていれば簡単に発行できますので、Google検索などで取得方法を確認し、発行して下さい。
取得できるAPIKeyには1日のアップロード、ダウンロードの上限があり、10,000ユニットという範囲で動作が可能です。上限を超えると、レスポンスが返らなくなりますが、翌日にはまた10,000ユニットが与えられます。
【ChannelIDの取得】
ChannelIDはGoogleでチャンネル名を検索し、URL部分に「https://www.youtube.com/channel」とあれば「channel」以降の部分がChannelIDです。
Advanced REST Clientを使ってURLをたたいてみる
ChatGPTの回答からYoutubeAPIの問合せURLは
「https://www.googleapis.com/youtube/v3/search?key=APIKEY&channelId=CHANNELID&part=snippet,id&order=date」
だとわかりましたが、ChatGPTの回答は正しいとは限りません。問合せが実行できることを確認するためにAdvanced REST Clientを使ってレスポンスが返ってくることを確認します。
※APIKEY、CHANNELIDの部分はご自分で取得した値にそれぞれ変更して下さい。
LotusScriptを使ってYoutubeAPIを実行してみる
LotusScriptを使ってYoutubeAPIを実行してみます。NotesV10以降はNotesHTTPクラスが追加されましたが、バイナリなどが扱えないため、昔ながらの「MSXML2.ServerXMLHTTP.6.0」を使用します。
実行するとYoutubeAPIから取得したレスポンスがメッセージボックスに表示されます。
【ソース】
Sub Click(Source As Button)
'---------- ---------- ---------- ---------- ----------
'YoutubeAPIから取得したレスポンスをMsgboxに表示
'
'---------- ---------- ---------- ---------- ----------
Const APIURL = "https://www.googleapis.com/youtube/v3/search?key="
Const APIKEY = "(取得したAPIKEY)" 'APIKey
Const CHANNELID = "(検索したChannelID)" 'ChannelID
'クラス・変数宣言
Dim vXml As Variant 'XMLオブジェクト
Dim sUrl As String '送信するURL
Dim vResponse As Variant 'HTTPRequestからの戻り値
'フィールドの値を取得して、リクエストURIを生成(指定のチャンネルから日付の新しい順に取得、件数を指定しないと5件取得される)
sUrl = APIURL + APIKEY + "&channelId=" + CHANNELID + "&part=snippet,id&order=date"
'Getリクエストを実行し、結果を取得
Set vXml = CreateObject("MSXML2.ServerXMLHTTP.6.0")
vXml.Open "GET", sUrl, False
vXml.send ""
Msgbox vXml.responseText
Msgbox "Done!"
End Sub
【レスポンスのデータ構造】
YoutubeAPIから取得したレスポンスをNotesJSONクラスを使って文書に保存する
YoutubeAPIで取得したレスポンスをNotesJSONクラスを利用して、必要な項目を文書に保存します。フォームを作成し「Title、VideoId、Thumbnail、ChannelTitle、Response」の5つのフィールドを配置します。一度の問合せでYoutubeAPIから取得できる動画の数は5つですので下記のコードで作成される文書数は最大で5文書となります。
【ソース】
Sub Click(Source As Button)
'---------- ---------- ---------- ---------- ----------
'YoutubeAPIから取得したレスポンスをJSONに分解し、文書として登録
'
'---------- ---------- ---------- ---------- ----------
Const APIURL = "https://www.googleapis.com/youtube/v3/search?key="
Const APIKEY = "(取得したAPIKEY)" 'APIKey
Const CHANNELID = "(検索したChannelID)" 'ChannelID
'クラス・変数宣言
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim jsonNav As NotesJSONNavigator
Dim vXml As Variant 'XMLオブジェクト
Dim sUrl As String '送信するURL
Dim vResponse As Variant 'HTTPRequestからの戻り値
Dim iItemCnt As Integer 'JSONオブジェクト件数
Dim iCnt As Integer 'ループカウンタ
'フィールドの値を取得して、リクエストURIを生成(指定のチャンネルから日付の新しい順に取得、件数を指定しないと5件取得される)
sUrl = APIURL + APIKEY + "&channelId=" + CHANNELID + "&part=snippet,id&order=date"
'Getリクエストを実行し、結果を取得
Set vXml = CreateObject("MSXML2.ServerXMLHTTP.6.0")
vXml.Open "GET", sUrl, False
vXml.send ""
'レスポンスをJSONナビゲータに格納、リストの数を取得
Set jsonNav = session.CreateJSONNavigator(vXml.responseText)
iItemCnt = jsonNav.GetElementByName("items").Value.Size
'文書を作成し、Responseを保存
For iCnt = 0 To iItemCnt - 1
Set db = session.CurrentDatabase
Set doc = db.CreateDocument
doc.Form = "frmLevel2"
doc.Title = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/snippet/title").Value
doc.VideoId = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/id/videoId").Value
doc.Thumbnail = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/snippet/thumbnails/default/url").Value
doc.ChannelTitle = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/snippet/channelTitle").Value
doc.Response = vXml.responseText & Chr(13) & "<" & Cstr(iCnt) & ">"
Call doc.Save(True,True)
Next
Msgbox "Done!"
End Sub
【フォームイメージ】
YoutubeAPIを繰り返し呼出、文書を作成する
上記ソースでは、一度のレスポンスに含まれるレコード5件を分解し、5つの文書を登録しました。6件目以降のレコードを取得するには、レスポンスに含まれる「nextPageToken」の値を取得し、URLに追加します。
【2ページ目以降を取得するURL】
「https://www.googleapis.com/youtube/v3/search?key=APIKEY&channelId=CHANNELID&part=snippet,id&order=date&pageToken=NEXTPAGETOKEN」
【ソース】
Sub Click(Source As Button)
'---------- ---------- ---------- ---------- ----------
'YoutubeAPIから取得したレスポンスをJSONに分解し、文書として登録
'
'---------- ---------- ---------- ---------- ----------
Const APIURL = "https://www.googleapis.com/youtube/v3/search?key="
Const APIKEY = "(取得したAPIKEY)" 'APIKey
Const CHANNELID = "(検索したChannelID)" 'ChannelID
'クラス・変数宣言
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim jsonNav As NotesJSONNavigator
Dim vXml As Variant 'XMLオブジェクト
Dim sBaseUrl As String 'ベースURL
Dim sUrl As String '送信するURL
Dim vResponse As Variant 'HTTPRequestからの戻り値
Dim iItemCnt As Integer 'JSONオブジェクト件数
Dim iCnt As Integer 'ループカウンタ
Dim sNextPageToken As String '次のページを取得するためのトークン
Dim iTotalCnt As Integer
'Getリクエストを実行し、結果を取得
Set vXml = CreateObject("MSXML2.ServerXMLHTTP.6.0")
' 初回リクエストのURLを作成
sBaseUrl = APIURL + APIKEY + "&channelId=" + CHANNELID + "&part=snippet,id&order=date"
sUrl = sBaseUrl
iTotalCnt = 0
'nextPageTokenがnullになるまでループ
Do
vXml.Open "GET", sUrl, False
vXml.send ""
'リクエスト越えチェック
If vXml.Status = 403 Then
Msgbox "リクエスト越え",16,"Error"
Exit Sub
End If
'レスポンスをJSONナビゲータに格納、リストの数を取得
Set jsonNav = session.CreateJSONNavigator(vXml.responseText)
iItemCnt = jsonNav.GetElementByName("items").Value.Size
sNextPageToken = jsonNav.GetElementByPointer("/nextPageToken").value
'文書を作成し、Responseを保存(一度のResponseを分解)
For iCnt = 0 To iItemCnt - 1
Set db = session.CurrentDatabase
Set doc = db.CreateDocument
doc.Form = "frmLevel2"
doc.Title = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/snippet/title").Value
doc.VideoId = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/id/videoId").Value
doc.Thumbnail = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/snippet/thumbnails/default/url").Value
doc.ChannelTitle = jsonNav.GetElementByPointer("/items/" & Cstr(iCnt) & "/snippet/channelTitle").Value
doc.Response = vXml.responseText & Chr(13) & "<" & Cstr(iCnt) & ">"
Call doc.Save(True,True)
Next
'nextPageTokenを引数に渡し、次のURLを生成
sUrl = sBaseUrl & "&pageToken=" & sNextPageToken
iTotalCnt = iTotalCnt + 1
If iTotalCnt > 3 Then
Exit Sub
End If
Loop While(sNextPageToken <> "")
Msgbox "Done!"
End Sub
YoutubeAPIの問題(仕様)
これでYoutubeAPIから取得したレコードをNotes文書として登録することができるようになりました。しかしYoutubeAPIには問題があります。それは「同じレコードを複数回返す」と言うことです。これはYoutubeが使っているバックエンドDBの特性かと思います。レスポンスを優先し、同じレコードが返ってくるため、VideoIdなど一意に特定出来る項目を使って、既に登録済みの場合、文書を登録しないように制御する必要があります。LotusScriptを記述できる方であればここまでの解説で十分実装可能かと思いますので、宿題とさせていただきます。
次回予告
次回はいよいよ、サムネイル画像の取得とDXLを使ったイメージリソースの登録、登録したイメージリソースのビューへの表示を行います。
【参考リンク】
ノーツコンソーシアム大阪研究会 浜さんブログ
出直し!! ドミノ塾 (denaoshidomino.com)