1. はじめに
昨晩、熊倉さんから以下のダイレクトメッセージを受け取りました。
小林さん突然すみません!こちら原因わからなくて困っているようなのですが、もし理由すぐ分かるようでしたら教えていただけるとめちゃ助かります・・ 個人的には、画像URLでカバー設定してもたまに引っ張ってこれない(.htaccess周りとかの設定?)ケースがあるのでそれに引っ掛かってるのかなーとかありますが、api特有の動きってあったりします・・?
熊倉さんが受けた質問主は Google Books API のイメージを API 経由で Notion に埋め込みたいが失敗するという話でした。結局、検証の結果、API から画像ブロックは埋め込めないことを結論づけました。夜中にふと、プロパティならいけるのではと思い再検証してみました。以下その再検証記録です。最終的には再検証も失敗したのですが、失敗談も記録ではあるので、ここに残しておきます。
2. 再検証準備
テストするためのページが必要なので、まずは検証ページを作ります。検証自体もタスクなので、ショートカットで作成します。タスク開始するショートカットの説明はこちらです。私の場合は、Cmd-Option-]で起動し、「A new task」でタイトルを入れるだけです。hkob.hatenablog.com
検証ページが出来ました。
Google Books API は知らなかったので、検索したところここに解説がありました。
ちなみにサムネールの URL はこんな感じになるそうです。画像ファイルではなく単なる API 呼び出しなのですね。
https://books.google.com/books/content?id=Bdh_RQAACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api"
検証には NotionRubyMapping を使います。irb を立ち上げ、以下のコマンドを実行し、上で作ったページを取得しておきます。また、上記のリンクを url という変数に格納しておきます。
require "notion_ruby_mapping" include NotionRubyMapping token = ENV["NOTION_API_KEY"] NotionCache.instance.create_client token page = Page.find "ce85304228264674b8ba99694def2d4d" url = "https://books.google.com/books/content?id=Bdh_RQAACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api"
3. 昨晩の再現
3.1 Notion からの貼り付けたものを検証
まずは質問主ができるという Notion 上での貼り付けをやってみます。以下のような画面が出てきます。URL なので Create embed
が候補に出ていました。
まず、このブロックを検証してみます。このためブロックの link を取得します。
URL はこうなっています。Page ID の後に # があり、その後が Block ID になります。Block ID は 44368f420e0c44ddb5082a797843a48b
ということがわかりました。
https://www.notion.so/hkob/Google-Books-API-ce85304228264674b8ba99694def2d4d#44368f420e0c44ddb5082a797843a48b
このブロックを Block.find で取得してみます。embed で作成したのですが、内部では ImageBlock になっています。
b0 = Block.find "44368f420e0c44ddb5082a797843a48b" # => NotionRubyMapping::ImageBlock-44368f420e0c44ddb5082a797843a48b
中身を見てみましょう。確かに ImageBlock であり、URL は上記のリンクがそのままついています。
b0.block_json # => # {"type"=>"image", # "object"=>"block", # "image"=> # {"type"=>"external", # "external"=> # {"url"=>"https://books.google.com/books/content? id=Bdh_RQAACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api"}, # "caption"=>[]}}
3.2 ImageBlock の作成 (失敗)
質問主が失敗するという ImageBlock を作成してみます。Invalid image url というエラーで失敗しました。
b1 = page.append_block_children ImageBlock.new(url) /Users/hkob/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/notion_ruby_mapping-0.5.2/lib/notion_ruby_mapping/blocks/base.rb:97:in `append_block_children': {"object"=>"error", "status"=>400, "code"=>"validation_error", "message"=>"Content creation Failed. Fix the following: \nInvalid image url."} (StandardError) from (irb):12:in `<main>' from /Users/hkob/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>' from /Users/hkob/.rbenv/versions/3.1.2/bin/irb:25:in `load' from /Users/hkob/.rbenv/versions/3.1.2/bin/irb:25:in `<main>'
URL が画像のファイルと判断されていないためですね。API reference の Block object によると、URL は以下のものでなければならないようです。
Includes supported image urls (i.e. ending in .png, .jpg, .jpeg, .gif, .tif, .tiff, .bmp, .svg, or .heic)
3.3 EmbedBlock の作成 (失敗)
ImageBlock がダメなら EmbedBlock にしたらどうなるのかということでやってみました。作成自体は成功しています。
b1 = page.append_block_children EmbedBlock.new(url) # => NotionRubyMapping::EmbedBlock-ced41ce10eb8444aafac53f5ea2b4577
確かに EmbedBlock は作成されているのですが、これは画像としては認識されていません。 ちなみに、b1 の内容を確認してみると以下のようになりました。type が image であればよいのですが、残念ながら API からブロックタイプを変換することはできません。
b1.block_json => {"type"=>"embed", "object"=>"block", "embed"=> {"caption"=>[], "url"=>"https://books.google.com/books/content?id=Bdh_RQAACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api"}}
3.3 力技での対応 (失敗)
画像と認識されればいいのではということで、文字列に .jpg が入っていればいいのではという話になり、オプションでdummy=a.jpg
のようなものをつけてみました。しかし、オプションは画像かどうかの判断には使われていないようで失敗しました。
b2 = page.append_block_children ImageBlock.new("#{url}?dummy=a.jpg") /Users/hkob/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/notion_ruby_mapping-0.5.2/lib/notion_ruby_mapping/blocks/base.rb:97:in `append_block_children': {"object"=>"error", "status"=>400, "code"=>"validation_error", "message"=>"Content creation Failed. Fix the following: \nInvalid image url."} (StandardError)
ファイル名に相当する部分ということで、途中の content に jpg 拡張子をつけてみました。
b2 = page.append_block_children ImageBlock.new(url.gsub "content", "content.jpg") # => NotionRubyMapping::ImageBlock-581e98f8b8bb4e62a0c8aaa851391dab
作成には成功しましたが、画像 URL がおかしいとエラーになりました。当たり前ですね。
3.4 FileBlock として貼り付け (失敗)
URL を貼り付けられるものとして他には FileBlock があります。こちらでは確かに貼り付けられました。
b3 = page.append_block_children FileBlock.new(url) => NotionRubyMapping::FileBlock-029a1f7ee19d4c6bb1a377837856b2ea
確かに貼り付けはできましたが、これは期待するものではないですね。
3.5 検証時の結論
結局、熊倉さんとは「とりあえず適当な画像を使って ImageBlock を作成し、URL を近くに書いておく」という結論に達しました。一番簡単なのは caption かと思うので、以下のようにしてみました。
b4 = page.append_block_children ImageBlock.new("https://cdn.worldvectorlogo.com/logos/notion-logo-1.svg", ca ption: url) # => NotionRubyMapping::ImageBlock-460b7356cd054c29a89ebd503109911f
作成されたものはこちらです。
ここで、キャプションの内容をコピーし、メニューから Replace をクリックします。
Embed link でコピーした URL を貼り付けます。
画像に変換されました。キャプションは適当なものに変換するか消せばよいです。
4 再検証 (結局失敗)
昨晩は早く寝てしまったので、早朝に目が覚めてしまいました。この件を朝に記事にしようと考えていたところ、File & Image プロパティなら画像ファイルとして制約を受けないのではと思いつきました。ということで、再検証スタートです。タイミングがいいことに昨日、インラインデータベースが作成できるようになりましたので、早速使ってみます。
db = page.create_child_database "Google Books", TitleProperty, "Title", FilesProperty, "Thumbnail" do |d, dp| d.is_inline = true end
インラインデータベースが作成できるようになったのはいいですね。あとはビューも作れるといいのですが。
仕方ないので、ビューは手動でギャラリービューに変換しました。
早速、データベースの下にページを作成してみました。URL が長すぎて、name の文字数制限に引っかかるようになってしまったので、file_names を別途設定できるように NotionRubyMapping を v0.5.5 にアップデートしました。
p0 = db.create_child_page do |p, pp| pp["Title"].text_objects << "我輩は猫である" pp["Thumbnail"].files = url pp["Thumbnail"].file_names = "thumbnail" end
作成はできましたが、画像は表示されませんでした。
ページを確認してみたところ、Thumbnail とだけ書かれています。ページにつけた時と同様に単なるファイルリンクと認識されているだけのようです。
View original とするとちゃんと画像は表示されます。
URL を取得し、上の「Add a file or image」に貼り付けてみます。 もっと悪い結果になり、URL だけが見えた状態になりました。クリックすると画像は開くのですが、思った結果ではありませんでした。
5. おわりに
FileProperty なら行けるのではと考えたのですが、やはり無理でした。せめて URL が画像だとわかる形になっていればよかったのですが、Google Books API ではうまくいかないようです。何にせよ、こんな感じの検証には NotionRubyMapping は便利だなというのを再認識しました。作ってよかったです。