🤖

MacOSでの自動ファイル転送システム構築ガイド

に公開

導入背景

私は整理整頓が好きで、スクリーンショットの保存先やChromeのダウンロードフォルダなんかを一つにまとめないと気が済まないタイプです。これらは設定により保存先を任意のフォルダに変更することが可能ですが、AirDropで受信したファイルの転送先フォルダは、macOSの仕様上変更することができません。

最初はmacOS純正のオートメーション機能である「Automator」を使用してファイルの移動を試みました。しかしAirDropの転送元であるダウンロードフォルダをトリガーとして指定した際に動作しないという問題が発生しました(方々調査しましたが解決しませんでした、MacOSのバグっぽい)。そこで、Node.jsを使用した独自の自動ファイル転送システムを構築することにしました。これは実質的に「Automator」の機能を自作したものです。

システム概要

このシステムは、指定したフォルダ(例:ダウンロードフォルダ)に新しいファイルが追加されると、それを自動的に別の指定フォルダに移動させる仕組みです。主な特徴:

  • Node.jsとchokidarライブラリを使用してファイルシステムの変更を監視
  • macOSの起動時および定期的に自動実行される
  • 転送結果をログ出力

必要な環境

  • macOS
  • Node.js(バージョン14以降推奨)
  • Terminal.appへのフルディスクアクセス権限

設定手順

1. 必要なファイルとフォルダの準備

  1. プロジェクトフォルダを作成:
mkdir -p ~/file-transfer
cd ~/file-transfer

  1. Node.jsのプロジェクトを初期化:
npm init -y
npm install chokidar

  1. ファイル転送スクリプト (file-transfer.js) を作成:
// フォルダAの新規ファイルをフォルダBに自動的に移動するスクリプト
const fs = require('fs');
const path = require('path');
const chokidar = require('chokidar'); // ファイル監視用ライブラリ

// 監視するフォルダと移動先フォルダのパスを設定
const sourceFolder = '/Users/ユーザー名/Downloads';              // 監視するフォルダ
const destinationFolder = '/Users/ユーザー名/指定の移動先フォルダ'; // 移動先フォルダ

console.log('監視フォルダ:', sourceFolder);
console.log('移動先フォルダ:', destinationFolder);

// フォルダが存在するかを確認し、なければ作成
if (!fs.existsSync(sourceFolder)) {
  console.error(`監視フォルダが存在しません: ${sourceFolder}`);
  process.exit(1);
}

if (!fs.existsSync(destinationFolder)) {
  fs.mkdirSync(destinationFolder, { recursive: true });
  console.log(`移動先フォルダを作成しました: ${destinationFolder}`);
}

// ファイル監視を設定
const watcher = chokidar.watch(sourceFolder, {
  persistent: true,
  ignoreInitial: true, // 既存ファイルは無視
  awaitWriteFinish: {
    stabilityThreshold: 2000, // ファイル書き込み完了を2秒間待機
    pollInterval: 100
  }
});

console.log(`フォルダの監視を開始しました: ${sourceFolder}`);

// 新しいファイルが追加されたときのイベントハンドラ
watcher.on('add', (filePath) => {
  const fileName = path.basename(filePath);
  const destinationPath = path.join(destinationFolder, fileName);

  // ファイルを移動先フォルダに移動
  fs.rename(filePath, destinationPath, (err) => {
    if (err) {
      console.error(`エラー: ファイル移動中にエラーが発生しました - ${filePath}`, err);
      return;
    }
    console.log(`ファイルを移動しました: ${fileName} => ${destinationPath}`);
  });
});

// エラーハンドリング
watcher.on('error', (error) => {
  console.error(`監視エラー:`, error);
});

// 例: Ctrl+C でスクリプトを終了する場合のクリーンアップ
process.on('SIGINT', () => {
  watcher.close();
  console.log('監視を終了しました');
  process.exit(0);
});

重要: sourceFolderdestinationFolderのパスを実際のパスに置き換えてください。例えば:

  • sourceFolder: /Users/ユーザー名/Downloads(ダウンロードフォルダ)
  • destinationFolder: /Users/ユーザー名/Documents/整理済みファイル(任意の移動先フォルダ)
  1. 起動スクリプト (file-transfer.sh) を作成:
#!/bin/bash

# ログファイルのパス設定
LOG_DIR="$HOME/logs"
LOG_FILE="$LOG_DIR/file-transfer.log"

# ログディレクトリがなければ作成
mkdir -p "$LOG_DIR"

# スクリプトのパスを設定
SCRIPT_DIR="$HOME/file-transfer"
cd "$SCRIPT_DIR"

# 日時を記録
echo "$(date): スクリプトを起動しています..." >> "$LOG_FILE"

# Node.jsスクリプトを実行
/usr/local/bin/node file-transfer.js >> "$LOG_FILE" 2>&1 &

echo "$(date): スクリプト起動プロセスが完了しました" >> "$LOG_FILE"

シェルスクリプトが必要な理由:
macOSのログイン項目として登録するためには、実行可能なシェルスクリプトが必要です。Node.jsスクリプト(file-transfer.js)を直接登録することはできないため、シェルスクリプト(file-transfer.sh)を介して起動する必要があります。

また、シェルスクリプトを使用することで以下のような利点もあります:

  • ログファイルへの出力が可能
  • バックグラウンドでの実行
  • エラー出力の適切な処理
  1. シェルスクリプトに実行権限を付与:
chmod +x file-transfer.sh

この実行権限の付与はmacOSのセキュリティ機構上必須です。これにより、シェルスクリプトが実行可能ファイルとして認識されます。

2. 自動起動設定

macOSのログイン項目に追加して自動実行するよう設定します:

  1. Appleメニュー(左上のリンゴマーク)→「システム設定」→「一般」→「ログイン項目」を開く
  2. 「+」ボタンをクリックする
  3. 作成したfile-transfer.shスクリプトを選択して「開く」をクリック

これにより、ユーザーがログインするたびに自動的にスクリプトが実行されます。

3. 権限設定

macOSのセキュリティ設定でTerminalにフルディスクアクセス権限を与える必要があります:

  1. 「システム設定」→「プライバシーとセキュリティ」→「フルディスクアクセス」を開く
  2. 左下の鍵アイコンをクリックして変更を許可(パスワード入力が必要)
  3. 「+」ボタンをクリックして「ターミナル」アプリを追加
  4. 「許可」をクリックして確定

権限設定が必要な理由:

macOSはセキュリティ保護のため、アプリケーションがシステムの重要なフォルダ(特にユーザーのプライバシーに関わるフォルダ)にアクセスすることを制限しています。この権限設定が必要な具体的な理由は:

  1. サンドボックス保護の回避: macOSはアプリケーションを「サンドボックス」内で実行し、他のフォルダへのアクセスを制限します。ダウンロードフォルダは特に保護されたフォルダの一つです。
  2. ファイルシステム監視の許可: chokidarライブラリはファイルシステムの変更を監視するために低レベルのシステムAPIを使用します。これらのAPIにアクセスするには特別な権限が必要です。
  3. EPERMエラーの防止: 権限がないと「EPERM: operation not permitted」というエラーが発生し、ファイルの移動ができません。これはmacOSの「透過的セキュリティ機能」(TCC:Transparency, Consent, and Control)によるものです。
  4. 自動起動スクリプトの実行: ログイン項目として登録されたスクリプトは、通常のユーザー権限で実行されるため、保護されたフォルダにアクセスするためには明示的な許可が必要です。

4. 動作確認

  1. スクリプトを手動で実行:
~/file-transfer/file-transfer.sh

  1. プロセスが起動しているか確認:
ps aux | grep node | grep -v grep

正常に起動していれば、file-transfer.jsを実行しているNode.jsのプロセスが表示されます。

  1. ログファイルを確認:
cat ~/logs/file-transfer.log

  1. テストファイルを作成して動作確認:
touch ~/Downloads/test_file.txt

  1. 移動先のフォルダを確認:
ls -la "~/指定の移動先フォルダ"

テストファイルが移動先フォルダに移動されていれば成功です。

応用例

このスクリプトは様々な用途に応用できます:

  • スクリーンショットの自動整理(~/Desktopを監視して特定のパターンのファイルを移動)
  • AirDropで受信したファイルの自動仕分け
  • 一時ファイルの自動クリーンアップ

まとめ

このガイドでは、macOSでNode.jsを使用して自動ファイル転送システムを構築する方法を解説しました。これにより、ダウンロードフォルダなどに追加されたファイルを任意のフォルダに自動的に移動させることができます。

macOSのAutomatorで実現できなかった機能も、Node.jsとchokidarライブラリを使えば柔軟に実装できます。自分の作業環境や好みに合わせてカスタマイズしてみてください。

Bizlink Developers Blog

Discussion