userdefinedscheduler_ja - noonworks/Nursery GitHub Wiki

UserDefinedSchedulerプラグイン

UserDefinedSchedulerプラグインは、ユーザーが自分で定義したスケジュールで、Botからのメッセージ送信および音声読み上げを行えるプラグインです。

1. プラグインの有効化

標準で有効化されています。特に操作は必要ありません。

2. ユーザー定義スケジュールを追加する

2-1. ユーザー定義スケジュールを作成する

標準では、Nurseryのフォルダ内のschedules以下に、ユーザー定義スケジュールの設定を保存します。フォルダがない場合は作成してください。

その後、schedules\three_minutes.jsonとして、以下のファイルを保存します。

{
  "name": "three_minutes",
  "conditions": [
    {
      "type": "interval",
      "interval_minutes": 3,
      "interval_start_option": "run_next"
    }
  ],
  "processes": [
    {
      "type": "send_message",
      "values": [
        "3分が経過しました。 ${count} / ${total_count} [${HH}:${mm}]"
      ]
    }
  ]
}

2-2. ユーザー定義スケジュールを実行する

ファイルを追加した後、Nurseryを起動し、入室させます。その後3分が経過すると、botが以下のような発言をします。

3分が経過しました。 1 / 1 [06:35]
  • その後も、3分経過するたびに同様の発言をします。
  • botをbyeなどで退室させると、3分が経過しても、発言をしません。
  • 1 / 1実行回数 / 合計実行回数です。実行のたびに増えていきます。
    • 実行回数は、入室してから実行した回数です。一度退室すると、0にリセットされます。
    • 合計実行回数は、スケジュール設定が読み込まれてから実行した合計回数です。
  • [06:35]は現在時刻です。botはPCのローカル時刻を参照しているため、Discordのサーバー時刻とはずれる可能性があります。

3. コマンド

3-1. @nursery-bot udsreload

ユーザー定義スケジュールを再読み込みするコマンドです。

通常、ユーザー定義スケジュールはNursery起動時に自動で読み込まれるので、このコマンドを使用する必要はありません。ただし、Nursery起動中に設定を変更した場合、変更した分は自動で再読み込みされません。その場合にこのコマンドを使って再読み込みします。

4. ユーザー定義スケジュール設定詳細

  • 設定ファイルはJSON形式です。
  • 必要に応じて "\ などはJSON形式のエスケープをしてください。

4-1. スケジュールの設定

{
  "name": "name_of_this_schedule",
  "conditions": [],
  "processes": []
}
  • name : このスケジュールの名前を指定します。任意の名前を付けます。
  • conditions : スケジュールが実行される条件を、配列で指定します。どれかひとつの条件が成立した場合、スケジュールが実行されます。
  • processes : スケジュールの実行内容を、配列で指定します。すべてが実行されます。

4-2. 実行条件

4-2-1. 間隔条件(インターバル条件)

  • 「指定した時間ごとに、定期的に起動する」という条件です。
  • 分単位での設定が可能です。
  • Botがボイスチャットに入室している間のみ起動します。
    {
      "type": "interval",
      "interval_minutes": 3,
      "interval_start_option": "run_next",
      "interval_start_at": ""
    }
  • type : "interval"を指定します。
  • interval_minutes : 間隔(分)を数値で指定します。
  • interval_start_option : 間隔の計算開始タイミングを指定します。
    • "run_on_join" : Botが入室したときに、すぐ1回目を実行します。
    • "run_next" : Botが入室したときには実行せず、次から実行します。
    • "not_start" : Botが入室しても、間隔の計算を開始しません。(他の条件と組み合わせるときに使います。)
    • "start_at" : interval_start_atで指定した日時から間隔の計算をします。
  • interval_start_at : 間隔の計算を開始する日時を指定します。
    • interval_start_option"start_at"のときのみ有効です。
    • 日時はyyyy.MM.dd-HH:mm形式で指定します。(例:2018年8月14日21時3分は2018.08.14-21:03

4-2-2. 時間範囲条件

  • 「指定した範囲の時間に該当した場合、起動する」という条件です。
  • 分単位での設定が可能です。
  • Botがボイスチャットに入室している間のみ起動します。
  • 時間範囲に該当した最初の1回のみ、スケジュールが実行されます。
    • 例:「9:00から12:00まで」という範囲の場合
      • 9:00にスケジュールが実行された場合、9:01や10:00、11:30などにはスケジュールは実行されません。
      • 9:00にはBotが入室しておらず、9:45に入室した場合、入室時にスケジュールが実行されます。
      • 9:00にスケジュールが実行された場合、次にスケジュールが実行されるのは、以下のタイミングです。
        • 12:00までの間に、Botが一度退室して再入室したとき
        • 12:00までの間に、ユーザー定義スケジュール設定の再読み込みコマンドが実行されたとき
        • 翌日の9:00
    {
      "type": "time_range",
      "time_range_start": 900,
      "time_range_end": 1200,
      "time_range_date_pattern": "",
      "time_range_use_previous_day": false
    }
  • type : "time_range"を指定します。
  • time_range_starttime_range_end : 時間範囲の開始と終了を数値で指定します。
    • 時刻を最大4桁の数字で指定します。9:30は930、22:53は2253、0:03は3、0:00は0になります。
    • ここで指定した数値の時刻自体は範囲に含まれます。
    • 開始 > 終了の場合、日をまたいだ設定とみなします。
      • 開始が2100で終了が100の場合、21:00から翌日の1:00までとみなす。
  • time_range_date_pattern : 日付の条件を指定します。
    • DateTimeMatcherの書式で指定します。
    • デフォルトは空(指定なし)です。
    • 例えば「火曜日の21時から23時」といった範囲を指定可能です。
  • time_range_use_previous_day : 日付をまたいた設定の場合で、基準の日を前日にするオプションです。
    • 通常、日付をまたいだ設定では、「当日から翌日にかけて」の設定とみなします。「当日」がtime_range_date_patternの判定に使われる基準の日になります。
    • time_range_use_previous_daytrueにすると、日付をまたいだ設定を「前日から当日にかけて」とみなします。「当日」がtime_range_date_patternの判定に使われる基準の日になります。
    • 使用例は後述のサンプルを確認してください。

4-2-2-1. 時間範囲条件サンプル① 毎日21:00~22:30

    {
      "type": "time_range",
      "time_range_start": 2100,
      "time_range_end": 2230
    }
  • time_range_date_patternがないので、毎日条件に一致します。

4-2-2-2. 時間範囲条件サンプル② 毎週火曜22:30~翌日1:00

    {
      "type": "time_range",
      "time_range_start": 2230,
      "time_range_end": 100,
      "time_range_date_pattern": "****.**.**-*2-**:**"
    }
  • time_range_date_pattern*2が火曜を表します。(DateTimeMatcherの書式
  • 開始(2230) > 終了(100)なので、日をまたいだ設定とみなされます。
  • 「当日から翌日にかけて」の設定とみなされます。(当日=time_range_date_patternの基準になる日=火曜)

4-2-2-3. 時間範囲条件サンプル③ 毎月、前日~最終日曜の深夜

    {
      "type": "time_range",
      "time_range_start": 2300,
      "time_range_end": 100,
      "time_range_date_pattern": "****.**.**-L0-**:**",
      "time_range_use_previous_day": true
    }
  • time_range_date_patternL0が最終日曜日を表します。(DateTimeMatcherの書式
  • 「最終日曜の前日」は最終土曜とは限らない(月末が土曜の場合は月が変わる)ので、time_range_use_previous_dayを使って「前日から当日」(当日=time_range_date_patternの基準になる日=最終日曜)に設定しています。

4-2-3. 日時条件

  • 「指定した日時に該当した場合、起動する」という条件です。
  • Botがボイスチャットに入室している間のみ起動します。
  • 指定日時に該当した最初の1回のみ、スケジュールが実行されます。
    • 詳細は後述のサンプルを参照してください。
    {
      "type": "date_time",
      "date_time_pattern": ""
    }
  • type : "time_range"を指定します。
  • time_range_date_pattern : 日時条件をDateTimeMatcherの書式で指定します。

4-2-3-1. 日時条件サンプル① 毎時10分(1)

    {
      "type": "date_time",
      "date_time_pattern": "****.**.**-**-**:10"
    }
  • 分以外の条件がないので、毎時10分に起動します。
    • 10分にBotが入室しておらず、15分に入室した場合、次の10分に起動します。

4-2-3-2. 日時条件サンプル② 毎時10分(2)

    {
      "type": "date_time",
      "date_time_pattern": "****.**.**-**-**:1*"
    }
  • 分以外の条件がないので、毎時1*分に起動します。
    • 基本的には10分に起動します。
    • 10分にBotが入室しておらず、例えば15分に入室した場合、15分に起動します。

4-2-3-3. 日時条件サンプル③ 12時台

    {
      "type": "date_time",
      "date_time_pattern": "****.**.**-**-12:**"
    }
  • 時以外の条件がないので、毎日12時に起動します。
    • 基本的には12時に起動します。
    • 12時にBotが入室しておらず、例えば12:40に入室した場合、12:40に起動します。

4-2-4. 関数条件

  • JavaScriptの関数を使って条件を記述します。
  • Botがボイスチャットに入室している間のみ起動します。
  • 関数はfunction_strもしくはfunction_fileのどちらかで指定します。
  • 関数が長い場合、function_fileを使った方が管理が楽になります。
    {
      "type": "function",
      "function_str": "",
      "function_file": "",
      "function_name": ""
    }
  • type : "function"を指定します。
  • function_str : JavaScriptコードを文字列で指定します。エスケープを忘れないよう注意してください。関数の仕様は後述します。function_fileが指定されていた場合、function_strは無視されます。
  • function_file : JavaScriptコードの記述されたファイルのパスを文字列で指定します。関数の仕様は後述します。
  • function_name : 関数名を文字列で指定します。function_strもしくはfunction_fileで指定したJavaScriptコードのうち、ここで指定した関数が呼ばれます。
function function_name(obj) {
  // ...
  return true;
}
  • 関数は、JSScheduleArgument型の引数1つを受け取り、bool型の結果を返します。
    • trueを返した場合、条件が成立したとみなします。
    • falseをを返した場合、条件が成立しなかったとみなします。
  • JSScheduleArgument型およびそのメンバの型についてはJavaScriptから使用可能なインターフェースを参照してください。

4-2-4-1. JavaScript関数の例

設定ファイルと関数ファイルのセットをschedulesフォルダに保存します。

  • 設定ファイル sec30.json
{
  "name": "sec30",
  "conditions": [
    {
      "type": "function",
      "function_name": "sec30_condition",
      "function_file": "sec30_condition.js"
    }
  ],
  "processes": [
    // 以下の内容についてはセクション4.3.3で解説
    {
      "type": "function",
      "function_name": "sec30_process",
      "function_file": "sec30_process.js"
    }
  ]
}
  • 関数ファイル sec30_condition.js
// 秒針が0秒か30秒のときにスケジュールを実行するよう設定する条件関数
function sec30_condition(obj) {
  var now = new Date();
  // 現在日時を文字列化する。
  var now_str = '' + now.getFullYear() +  '/' +
    ('00' + (now.getMonth() + 1)).slice(-2) + '/' +
    ('00' + now.getDate()).slice(-2) + ' ' +
    ('00' + now.getHours()).slice(-2) + ':' +
    ('00' + now.getMinutes()).slice(-2) + ':' +
    ('00' + now.getSeconds()).slice(-2);
  // obj.Scheduler.AdditionalData は、各スケジュールが持つ変数で、
  // JS関数が任意の文字列を保存・参照してよい。
  // ここでは「前回の実行日時」を保存する。
  // 前回の実行日時が現在日時と同一の場合、重複して実行しないようにする。
  if (obj.Scheduler.AdditionalData == now_str) { return false; }
  // 実行するか判定する。(秒針が0か30)
  var run = (now.getSeconds() % 30 == 0);
  // 実行する場合、現在日時を「前回の実行日時」として
  // obj.Scheduler.AdditionalData に保存する。
  if (run) { obj.Scheduler.AdditionalData = now_str; }
  return run;
}

4-3. 実行内容

4-3-1. メッセージの送信

  • BotからDiscordにメッセージを送信します。
    {
      "type": "send_message",
      "values": [],
      "send_to_type": "default",
      "send_to": [],
      "cut_if_too_long": true
    }
  • type : "send_message"を指定します。
  • values : 送信するメッセージを文字列の配列で指定します。
  • send_to_type : 送信先の種類を指定します。
    • default : デフォルトのテキストチャンネル(Botを呼ぶときに使ったテキストチャンネル)に送信します。
    • all : Botが参加しているすべてのテキストチャンネルに送信します。
      • ただし、${announce}${speak}のラベルは1つ目のチャンネルにしか送信されません。
    • channels : send_toで指定したテキストチャンネル(複数可)に送信します。
      • ただし、${announce}${speak}のラベルは1つ目のチャンネルにしか送信されません。
  • send_to : メッセージを送信するテキストチャンネルのIDを、文字列の配列で指定します。
    • send_to_typechannelsのときのみ有効です。

4-3-2. 文章の読み上げ

  • 棒読みちゃんでの文章読み上げを行います。
  • Discordにはメッセージを送信しません。
    {
      "type": "talk",
      "values": []
    }
  • type : "talk"を指定します。
  • values : 読み上げる文章を文字列の配列で指定します。

4-3-3. 関数の実行

  • JavaScriptの関数を実行します。
  • 関数はfunction_strもしくはfunction_fileのどちらかで指定します。
  • 関数が長い場合、function_fileを使った方が管理が楽になります。
    {
      "type": "function",
      "function_str": "",
      "function_file": "",
      "function_name": ""
    }
  • type : "function"を指定します。
  • function_str : JavaScriptコードを文字列で指定します。エスケープを忘れないよう注意してください。関数の仕様は後述します。function_fileが指定されていた場合、function_strは無視されます。
  • function_file : JavaScriptコードの記述されたファイルのパスを文字列で指定します。関数の仕様は後述します。
  • function_name : 関数名を文字列で指定します。function_strもしくはfunction_fileで指定したJavaScriptコードのうち、ここで指定した関数が呼ばれます。
function function_name(obj) {
  // ...
  return [];
}
  • 関数は、JSScheduleArgument型の引数1つを受け取り、ScheduledMessage[]型の結果を返します。
    • 結果のScheduledMessage[]すべてについて、メッセージの送信もしくは文章の読み上げが行われます。
    • nullを返した場合、メッセージの送信および文章の読み上げは行われません。
  • JSScheduleArgument型、ScheduledMessage型およびそのメンバの型についてはJavaScriptから使用可能なインターフェースを参照してください。

4-3-3-1. JavaScript関数の例

設定ファイルと関数ファイルのセットをschedulesフォルダに保存します。

  • 設定ファイル sec30.json

セクション4.2.4で例示したsec30.jsonファイルを参照してください。

  • 関数ファイル sec30_process.js
// sec30_conditionに対応する処理関数
function sec30_process(obj) {
  // obj.Scheduler.AdditionalData から実行日時を取得する。
  var add_data = obj.Scheduler.AdditionalData;
  // 結果用変数を生成する。
  var msg = new ScheduledMessage();
  // 結果の本文を設定する。
  if (add_data == null || add_data.length == 0) {
    // 実行日時が取得できなかった場合は「エラー」を本文とする。
    msg.Content = 'エラー';
  } else {
    // 実行日時が取得できた場合はそれを本文とする。
    msg.Content = add_data;
  }
  // 結果用変数のクローンを作成
  var msg2 = msg.Clone();
  // 結果用変数をメッセージ送信として設定
  msg.Type = ScheduledMessageType.SendMessage;
  // クローンを文章読み上げとして設定
  msg2.Type = ScheduledMessageType.Talk;
  // 2つを配列で返す。
  // →同じ内容で、Discordへのメッセージ送信と棒読みちゃんでの文章読み上げが両方行われる。
  return [msg, msg2];
}

5. プラグインの無効化

  1. plugins\plugins.jsonをメモ帳などで開きます。
  2. Nursery.UserDefinedSchedulerPlugin.で始まる行を削除します。
  3. 上書き保存してメモ帳を閉じます。
  4. 次回の起動時から、UserDefinedSchedulerプラグインが無効になります。