Notion に基づく P.A.R.A 実践(2)#
自 Notion に基づく P.A.R.A 実践(1) が公開されて以来、このシステムは少しの迭代アップグレードを経て、現在も 4 ヶ月使用しており、順調に動作しています!
Obsidian との使用体験を比較すると、ソフトウェアを開く必要がなく、手動でデータを同期したり、プラグインページをいじったりする複雑なプロセスが省かれました。また、Notion のオープン API インターフェースは、利便性と遊び心をさらに高めており、Notion をさまざまなビューで見ることができる非常に使いやすいデータベースとして利用できます。Calendar のリリースは、私がずっと欲しかった機能をもたらしました:カレンダーの中で自分が気にかける内容をカスタマイズすることです。今はまだ少し粗いですが、これが私が求めていた機能です。ブラウザのプラグインを組み合わせることで、私のすべての 「後で読む」 を Notion にまとめることができます。モバイル端末でも、読書ノートの記録をサポートするためにいくつかのショートカットを作成しました。テキストをコピーし、Apple の 「ダブルタップ」 と組み合わせるだけで、内容を Notion に同期できます。
全体の使用体験は非常にスムーズで、次に私がどのようなことを試したかを少し紹介します。
1. システムの変更#
- Resource
- 読む価値のある内容を記録するための Fav モジュールを追加しました。
- 購入した物品 / サービスの使用体験を記録するための Thing モジュールを追加しました。
- Archive
- 内容が多い Resource データベースに週ごとのグループ分けを追加しました。
2. メールサービス - ノートの同期#
- メールサーバー
imap
パッケージを使用してメールを監視し、mailparser
パッケージでメール内容を解析します。
-
参考コード
const Imap = require('imap') const MailParser = require('mailparser').MailParser const moment = require('moment') const logger = require('./logger')('sdk/logger') let emailCount = 10 console.log('-----サーバー起動-----' + moment().format('YYYY-MM-DD HH:mm:ss') + '-------------------------------------') let inflag = false function mailReceiver(userInfo, mailHandler) { let imap = new Imap(userInfo) imap.connect() setTimeout(() => imap.end(), 5 * 60 * 1000) // 5分ごとに接続を再構築 imap.once('ready', () => { setTimeout(() => { if (!inflag) { logger.warn(`接続できませんでした。再接続します。`) imap.end() } }, 30_000) imap.openBox('INBOX', false, () => { inflag = true imap.once('mail', num => { }) searchUnseen(imap, mailHandler) }) }) imap.on('mail', num => { if (num > emailCount) return // 大量のメールが流入するのを防ぐ searchUnseen(imap, mailHandler) }) imap.once('error', err => { logger.error(`接続失敗、再接続します ${err.message}`) mailReceiver(userInfo, mailHandler) }) imap.once('end', () => mailReceiver(userInfo, mailHandler)) } function searchUnseen(imap, mailHandler) { let timestr = (new Date(+new Date() - (5 * 60 * 1000))).toISOString() imap.search(['UNSEEN', ['SINCE', timestr]], (err, results) => { if (err) { logger.error('検索エラー' + err.mesasge) imap.end() return } if (results.length == 0) return try { let f = imap.fetch(results, { bodies: '', markSeen: true }) f.on('message', (msg, seqno) => { msg.on('body', (stream, info) => { let parser = new MailParser() stream.pipe(parser) let mail = {} parser.on("headers", headers => mail.headers = headers) parser.on("data", content => mail.content = content) parser.on('end', () => mailHandler(mail)) }) msg.once('end', () => { }) }) f.once('error', err => { logger.error(`メール受信エラー:${err.message}`) imap.end() }) f.once('end', () => imap.end()) } catch (err) { logger.error('検索エラー' + err.mesasge) imap.end() } }) } module.exports = mailReceiver
- Notion の同期
Notion の接続は内部統合と外部統合に分かれ、内部統合は比較的簡単で、トークンを取得するだけで済みます。外部統合は一整セットの認証を実装する必要がありますが、自分用には内部統合の方法で十分です。
詳細は公式ドキュメントを参照してください:最初の統合を構築する (notion.com)
-
参考コード
const { Client } = require("@notionhq/client") class PARA { constructor() { this.client = new Client({ auth: process.env.NOTION_TOKEN, // 申請したトークン }) } async findPageByName(pageName) { const res = await this.client.databases.query({ "database_id": this.database_id, filter: { property: 'Name', rich_text: { equals: pageName }, }, }) return res.results[0] } async addPage(item) { let { name, mediaType, author, startDate, endDate, remark, score, status, emoji, url } = item const page = await this.findPageByName(name) if (page) { return page } const data = { "parent": { "database_id": this.database_id }, "icon": { "emoji": emoji || "🥬" }, "cover": { "external": { "url": "https://upload.wikimedia.org/wikipedia/commons/6/62/Tuscankale.jpg" } }, "properties": { } } if (name) data.properties.Name = { "title": [ { "text": { "content": name } } ] } if (author) data.properties.Author = { "rich_text": [ { "text": { "content": author } } ] } if (remark) data.properties.Remark = { "rich_text": [ { "text": { "content": remark } } ] } if (status) data.properties.Status = { "status": { "name": status } } if (startDate) data.properties.Dates = { "type": "date", "date": { "start": startDate, } } if (endDate) data.properties.Dates = { "type": "date", "date": { "end": endDate } } if (startDate && endDate) data.properties.Dates = { "type": "date", "date": { "start": startDate, "end": endDate } } if (mediaType) data.properties.MediaType = { "select": { "name": mediaType } } if (url) data.properties.Url = { url } if (score) data.properties.Score = { "number": score } return this.client.pages.create(data) } async addBlock(item, content) { let page = await this.findPageByName(item.name) if (!page) { page = await this.addPage({ name: pageName }) } const res = await this.client.blocks.children.append({ block_id: page.id, children: [{ "type": "paragraph", "paragraph": { "rich_text": [{ "type": "text", "text": { "content": content, "link": null } }], "color": "default" } }] }) return res.results[0] } } class ResouceseArt extends PARA { constructor() { super() this.database_id = '' // あなたのデータベースID } } module.exports = { ResouceseArt }
**pm2
でサービスを実行 **
/**
* メールをNotionデータベースに同期するリスナー
*/
const mailListener = require('../sdk/mail-receiver')
const logger = require('../sdk/logger')('server/mail-sync-notion')
const { ResouceseArt, ResourceFlash, ResourceFav } = require('../sdk/notion-para')
let art = new ResouceseArt()
let userInfo = {
user: '[email protected]',
password: '',
host: 'outlook.office365.com',
port: 993,
tls: true
}
mailListener(userInfo, async (mail) => {
if (!mail) return
const subject = mail.headers.get('subject')
const text = mail.content.text
try {
if (subject.indexOf('flash') > -1) {
const page = await flash.addPage({ name: text, url: text })
logger.info('同期成功', { subject, text, page })
}
// その他の処理ロジック
} catch (err) {
logger.error('Notionの同期に失敗しました', { err })
}
})
-
ショートカットの追加
まず iPhone のメールアプリに送信者アカウントを追加し、次にメールを送信するショートカットを作成し、最後に設定でダブルタップを選択して作成したショートカットを選択します。
2.2 のコードを利用して TelegramBot や Cli などの方法で内容を Notion に同期することもできます。