はじめに
Notion Tips の第176回目は、3年前に作っていたらしい「選択中のテキストをコードブロックとして追加する macOSサービス」を、使いやすいように改修した話です。元々は、「Notion API を触ってみようの会」でのやり取りから始まっていました。
NotionキャンパスリーダーのHaruki(@Haruki_dev)とAsahi(@ashh_log)主催の【NotionAPIを触ってみようの会】に参加しています!! https://t.co/ZcZoRMPy6o #NotionAPIを触ってみようの会
— hkob|Notion Ambassador (@hkob) 2024年12月14日
その中で、豚角煮チー牛さんが Save Snippet to Notion の話をしており、こんなポストをしていました。
🚀 Save Snippet to Notion を作りました!🎉
— 豚角煮チー牛 CheeseGue / Notionテンプレートクリエイター (@CheeseGueNotion) 2024年12月10日
💻 VSCodeの拡張機能 で、選択したコードを✨ Notionのデータベース ✨に保存できます!
📋 手作業でコピペしていた作業が⏩ ショートカットキーだけ で完了!作業を中断せずにスムーズに保存可能です。🙌
💡🔗 #Notion #VSCode #効率化 pic.twitter.com/CvgWp8k8G1
その話を聞いて、そういえば私も昔作ったなと返信しました。
私も 3年くらい前に作っていたみたいです。最近、RubyMine ばかり使っていて、ほとんど VSCode をメインで使っていなくて忘れていました。今はずいぶん変わっているかもしれないから作り直そうかな。https://t.co/RAQ2FnV6qV
— hkob|Notion Ambassador (@hkob) 2024年12月14日
さらに調べると macOS のサービスも作っていたことが判明しました。この時の記事もはなてブログに掲載されています。
その後、macOS のサービスも作っていたらしい。マシンを入れ替えたりした時に入れ忘れて存在すら忘れていた。ちょっといろんなものを棚卸してみよう。https://t.co/E69mR54tOb
— hkob|Notion Ambassador (@hkob) 2024年12月14日
自分のサービスを確認してみたところ、そのまま残っていてショートカットキーを設定したらそのまま動いてしまいました。
3年前に作っていたらしいNotionCodeBlockQuickAction。ショートカットキーが外れていたので、設定したら今でも動いた。macOS のサービスなので、選択できるものならなんでも Codeblockに取り込んでくる。Notion-Versionが古いので、後でそれだけでもアップデートしておくか。https://t.co/VCNo4i9COS pic.twitter.com/LVtRnxbSvU
— hkob|Notion Ambassador (@hkob) 2024年12月14日
ただ、内容を調べてみると3年前の API で Notion-Version も古いし、特定のデータベースの最新のページに貼る仕様だったので、今の使い方だと不便でした。今回は、以下の改修をすることにしました。
- Notion-Version を最新の 2022-06-28 に変更
- Database query endpoint ではなく、Search endpoint にしてインテグレーションがつながっている任意のページの最新のものに貼り付けるように変更
これによって、ユーザばインテグレーションキーを登録するだけになり、他の人にも勧めやすくなります。
作成方法
普通の人は以下のリポジトリに最新版のバイナリがあるので、ダウンロードしてインテグレーションキーを設定すれば完了です。
ここでは、同じようなサービスを作ってみたい人もいると思うので、作成方法を解説しておきます。今回はサービスを生成するために、macOS の Automator を使います。
起動すると何を作成するか聞かれるので、「クイックアクション」を追加します。
アクションは以下の二つを連結しています。
- JavaScript を実行
- Web ページを表示
作成したスクリプト
基本は 1.0 の時とほぼ同様です。以下の変更をしています。
- getNotionPages の部分が
https://api.notion.com/v1/search
に変更 - 当時考慮していなかった 2000 文字を超える RichText を分割する処理を追加
- Notion-Version の更新に伴う text → rich_text の変更
特に 3 の変更はあまりに大昔すぎて、この変更があったことすら忘れていて時間がかかりました。NotionRubyMapping に JSON のお手本を書いてもらって判明しました。解決してよかったです。
// ########## Personal settings ########## // Set your Notion API Token (strings that starts with `ntn_` or `secret_`) const NOTION_API_TOKEN = "secret_XXXXXXXXXXXXXXXXXXXXXXXX" // Set default language const DEFAULT_LANGUAGE = "shell" // If you want to open a new task by Notion.app, set true. If you want to open it by your default browser, set false. const OPEN_BY_APP = true // Available languages const languages = [ "abap", "arduino", "bash", "basic", "c", "clojure", "coffeescript", "c++", "c#", "css", "dart", "diff", "docker", "elixir", "elm", "erlang", "flow", "fortran", "f#", "gherkin", "glsl", "go", "graphql", "groovy", "haskell", "html", "java", "javascript", "json", "julia", "kotlin", "latex", "less", "lisp", "livescript", "lua", "makefile", "markdown", "markup", "matlab", "mermaid", "nix", "objective-c", "ocaml", "pascal", "perl", "php", "plain text", "powershell", "prolog", "protobuf", "python", "r", "reason", "ruby", "rust", "sass", "scala", "scheme", "scss", "shell", "sql", "swift", "typescript", "vb.net", "verilog", "vhdl", "visual basic", "webassembly", "xml", "yaml", "java/c/c++/c#" ] // show a dialog to register dateTimeStr function dialogText(app, input) { const message = "Input language \n" + " Example: (no input) -> " + DEFAULT_LANGUAGE + "\n Available: " + languages.join(", ") + "\n for Message : \n" + input return app.displayDialog(message, { defaultAnswer: "", withIcon: "note", buttons: ["Cancel", "Continue"], defaultButton: "Continue" }) } // Call Notion API function sendNotion(app, url, payload, method) { const header = " --header 'Authorization: Bearer '" + NOTION_API_TOKEN + "'' " + "--header 'Content-Type: application/json' " + "--header 'Notion-Version: 2022-06-28' " + "--data '" const script = "curl -X " + method + " " + url + header + payload.replaceAll("'", '\'"\'"\'') + "'" return JSON.parse(app.doShellScript(script)) } function getNotionPages(app, payload) { const url = "https://api.notion.com/v1/search" return sendNotion(app, url, payload, "POST") } function getLastEditedPage(app) { const payload = { sort: { timestamp: "last_edited_time", direction: "descending" }, page_size: 1 } return getNotionPages(app, JSON.stringify(payload)) } function appendBlockChildren(app, pageId, payload) { const url = "https://api.notion.com/v1/blocks/" + pageId + "/children" return sendNotion(app, url, payload, "PATCH") } function appendCodeBlock(app, page, code, language) { if (page) { const pageId = page.id let texts = [] for (let i = 0; i < code.length; i+=1990) { texts.push({type: "text", text: {content: code.slice(i, i+1990)}}) } const payload = { children: [ { type: "code", object: "block", code: { rich_text: texts, language: language } } ] } const result = appendBlockChildren(app, pageId, JSON.stringify(payload)) return result.url } else { return null } } function run(input, parameters) { const app = Application.currentApplication() app.includeStandardAdditions = true if (input.length > 0) { const inputStr = String(input) three_lines = inputStr.match("^[^\n]+\n[^\n]+\n[^\n]+") || inputStr const response = dialogText(app, three_lines) if (response.buttonReturned == "Continue") { var language = response.textReturned if (languages.indexOf(language) == -1) { language = "shell" } const lastEditedPage = getLastEditedPage(app).results[0] appendCodeBlock(app, lastEditedPage, inputStr, language) var url = lastEditedPage.url if (OPEN_BY_APP == true) { url = url.replace("https", "notion") let notion = Application("Notion") notion.activate() } } return url } else { return false } }
利用方法
保存したら、キーボード - ショートカットのタグでショートカットを設定します。今回は、「Opt-Cmd-P」にしました。
コードブロックにしたいテキストを選択した状態で、設定したショートカットをタイプします。言語設定のダイアログが出るので、タイプします。デフォルトは shell になっています(スクリプト内で変更できます)。これによって、最後に編集したデータベースページの最後の部分にcode block が追加されます。
おわりに
今回の更新でタスクデータベースだけでなく、インテグレーションキーが結びついているレジュメのページなどにもコードを貼れるようになりました。すっかり忘れていましたが、これから便利に使っていきたいと思います。