n8n で URL を簡単にnextcloud notes にメモする

さて先日つくった Nextcloud + QOwnNotes のノートアプリ環境ですが、若干の不満はありますが、まずまずって感じです。

スマホだと(すくなくとも いPhone では) Evernote のような Webクリッピング機能がないことです。iPhone でブラウジング中に、このページちょっと見返す必要があるかもって時に、手数が多いのが面倒です。(デスクトップだとPluginがあるっぽい)

これを解消するために n8n で メモする URLを受取りマークダウンで保存するフローを作ります。

前回 の iPhone ショートカットアプリから POST リクエストする仕組みを使い、
ブラウザで共有 > ショートカットアプリで POST > n8n でマークダウン作成 > NextCloud ファイル保存
の流れができ URL を簡単にメモできるようにします。

NextCloud

n8n から NextCloud へのアクセスは公式のノードがありますが今回はあえて使いません。公式のノードでは NextCloud にアップロードしてファイルを作成するという正しい方法でおこなっています。

自分の環境では NextCloud がコンテナとして動作しているので万が一止まっていると、メモしたいものが消えてしまうので、直接ローカルファイルシステムに書き込んでいます。ローカルのフォルダを docker にマウントしてみえるようにしています。

この方法には1つ欠点があって、NextCloud からすると勝手に追加されたファイルを認識できないので、 occ コマンドでフォルダをスキャンしてやって初めて NextCloud の管理下に入れることができる。今回は systemd タイマーで解決することにした。

n8n

n8n のフローはごくシンプルです。

  • Webhook
  • Code
  • Read・Wrie Files from Disk

の3つのノードを使います。ただ順番につなげるだけです。

Webhook

HTTP Mothod: POST

に設定します。[Test URL]、[Production URL] の違いですが、編集画面でデバッグ実行できるのが [Test URL] です。Production の方は Execution ログには残りますが、途中で動作を止めたり、編集できないので注意。

これに気づかず [Test URL] のまま運用して保存(つまり n8n のフローが実行)されないことにしばらくきづきませんでした。

メッセージbody には以下のような JSON スキーマを期待しています。

{
  "tilte": "ページタイトル",
  "url": "メモしたいURL"
}

Code

キャプチャでは Generate Markdown という名前に変更していますが、それはお好みで。

// Get all input items
const allItems = $input.all();

// First item should have the HTML data from HTTP Request
const httpResponse = allItems[0].json;
const url = $('Webhook').first().json.body.url
const title = $('Webhook').first().json.body.title

// Generate filename with timestamp
const now = new Date($now);
const yyyy = now.getFullYear();
const mm = String(now.getMonth() + 1).padStart(2, '0');
const dd = String(now.getDate()).padStart(2, '0');
const hh = String(now.getHours()).padStart(2, '0');
const min = String(now.getMinutes()).padStart(2, '0');
const ss = String(now.getSeconds()).padStart(2, '0');
const filename = `${yyyy}${mm}${dd}-${hh}${min}${ss}.md`;

// Generate markdown content
const markdown = `title: ${title}\nurl: ${url}\n`;

// Return data with binary content
return [{
  json: {
    filename: filename,
    url: url,
    title: title
  },
  binary: {
    data: {
      data: Buffer.from(markdown, 'utf8').toString('base64'),
      mimeType: 'text/markdown',
      fileName: filename
    }
  }
}];

POST リクエストから JSON 取り出して、日時ベースのファイル名を決定し、マークダウン本文を構築して、次のノードにそれらを流しています。

Read / Write Files from Disk

Operation: Write File to Disk

File Path and Name: /保存したいパス/{{ $json.filename }}

$json.filename は前のノードから渡されたファイル名を指定している。

systemd timer

先述のとおり、 occ コマンドでスキャンする必要があるので、systemd タイマーを書く。もちろん cron でもいい。ファイル書くのは面倒だけど、こういうのこそ生成 AI が得意なので適当に下書きしてもらってなおすと楽。

cron は実行間隔の書き方を永遠に覚えられる気がしないので、その点だけが systemd timer が好きな理由。

[Unit]
Description=Nextcloud scan Notes folder
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
User=実行するユーザー名
ExecStart=/usr/bin/docker exec -u www-data nextcloud php occ files:scan --path="/保存先のフォルダ"
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

[Unit]
Description=Scan Nextcloud Notes/zzWorking folder every 5 minutes
Requires=nextcloud-scan.service

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
AccuracySec=1min

[Install]
WantedBy=timers.target

あとは

% sudo systemd daemon-reload
% sudo systemd enable nextcloud-scan.service
% sudo systemd start nextcloud-scan.service

で実行する。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です