追悼 Qiitadon
⇒ Misskey版
できること
- QiitaのMastodonインスタンス「Qiitadon (β)」へ、Windows PCのスリープ前後に定型文を投稿(Toot)します。
- 「Windowsで」、「スリープの前後に」がポイントです。
環境
- 初出時
- Windows 10 Pro (20H2)
- curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
- 最新
- Windows 11 Pro (22H2)
- curl 8.4.0 (Windows) libcurl/8.4.0 Schannel WinIDN
基本方針
- スリープ前
- これまでは、単純なスリープを実現するショートカットファイルに、キー(
Ctrl + Shift + Alt + Down
)を割り当てて使っていました。 - スクリプトを追加して、Tootしてからスリープするようにします。
- これまでは、単純なスリープを実現するショートカットファイルに、キー(
- スリープ後
- タスクスケジューラを使って、スリープ解除をトリガーにTootするようにします。
curlでTootする
以下のようなシェルスクリプトで実現しました。
qiitadon_nyahn.bat
curl -X POST -sS https://qiitadon.com/api/v1/statuses --header "Authorization: Bearer 《アクセストークン》" -d "status=%%e3%%81%%ab%%e3%%82%%83%%ef%%bd%%9e%%e3%%82%%93%%f0%%9f%%90%%88"
- 以下の記事を参考にさせていただきました。どうもありがとうございました。
- Tootするメッセージは、URLエンコードが必要です。
- バッチファイルでは、
%
が特殊文字として扱われるので、エスケープするために%%
と書く必要があります。
- バッチファイルでは、
- 「未収載」を指定する際は、
-d "visibility=unlisted"
を追加します。- バッチファイルでは、シングルクォートだと意図した通りになりません。
-
《アクセストークン》
は、Qiitadonの設定
>開発
画面で、新規アプリ
ボタンを押すと生成できます。- 後で分かるように適当な
アプリの名前
を付けて、アクセス権をwrite
だけにすれば、他はそのままでOKです。 - 万が一漏洩した際は、「アクセストークンの再生成」を行って差し替えてください。
- 後で分かるように適当な
スリープ前にTootする
以下のようなシェルスクリプトで実現しました。
Nyahn&SleepComputer.bat
start /wait /min cmd /C "qiitadon_nyahn.bat"
timeout /NOBREAK /T 10
powershell -WindowStyle Hidden -Command "Add-Type -Assembly System.Windows.Forms;[System.Windows.Forms.Application]::SetSuspendState('Suspend', $false, $false);"
- Tootした後、通信が完了するのを待つために、適当な時間をおいています。
- 時間をおかないとTootされませんでした。
- 必要な待ち時間は、PCや回線品質によって異なると思います。
- 最後の行は、私のPC向けのスリープですので、PCに合わせて適宜差し替えてください。
- powershellを使わなくても、
rundll32.exe powrprof.dll,SetSuspendState 0,1,0
とかで可能です。
- powershellを使わなくても、
- 最初は、(後述の「復帰後」のように)イベントで実現しようと試みたのですが、処理中にスリープしてしまうため、スリープ復帰後にTootされてしまいました。
- 試行で使用したトリガーは、「ログ: システム、ソース: Kernel-Power、イベントID: 42」です。
スリープ復帰後にTootする
タスクスケジューラで、以下のようなタスクを作りました。
- タスク 'nyahn'
- トリガー
- ログ: システム
- ソース: Power-Troubleshooter
- イベントID: 1
- 操作
- プログラムの開始: qiitadon_nyahn.bat
- トリガー
おまけ
- powershellを使っているのは、私のPC(BootCamp)では
rundll32
だと落ちるからです。 - 全てpowershellで書けば、もっとスマートにできそうですが、powershellの
curl
はInvoke-WebRequest
のエイリアスで、Invoke-WebRequest
は使い方が良く解りませんでした。
Windowsでスリープ前後にmisskey.devへ「にゃ~ん🐈」とノートする
- QiitaのMastodonインスタンス「Qiitadon (β)」は失われて久しいので、(個人的な)引っ越し先のMisskeyサーバ、misskey.devで同じことができるようにしました。
- バッチ処理内容の変更のみで起動方法に変更はありません。
- 3つのバッチファイルは同じフォルダに置かれることを想定しています。
curlでNoteする
note.bat
echo off
chcp 65001
set TEMPJSON=%TEMP%\note.json
if exist "%TEMPJSON%" goto done
echo {"i":"《トークン》","text":%1,"visibility":"public","visibleUserIds":[],"localOnly":true}>%TEMPJSON%
curl -X POST -H "Content-Type: application/json" -d "@%TEMPJSON%" https://misskey.dev/api/notes/create
del %TEMPJSON%
:done
- 文字コードをUTF-8に設定します。
- 一時ファイルを使うので、環境変数にパスを設定します。
- 既に実行中(一時ファイルが既存)であれば終了します。
- 一時ファイルとして、postするjsonを作ります。
-
《トークン》
は、設定>APIのToken
に置き換えてください。 -
"visibility":"specified","visibleUserIds":["《自分のID(@なし)》"]
とすれば、自分だけに見えるように投稿してテストできます。
-
- 一時ファイルをapi
notes/create
へpostします。 - 一時ファイルを削除します。
一時ファイルが残留する可能性
- 何らかの理由でバッチ処理が中断すると、一時ファイルが消えずに残って、以降、機能しなくなる可能性があります。
- 随時、何らかの安全なタイミングで、一時ファイルをクリアすることが望ましいです。(後述)
スリープ復帰後にNoteする
Nyahn.bat
echo off
chcp 65001
start /wait /min cmd /C "chcp 65001&%~dp0note.bat "にゃ~ん🐈""
- 二重引用符の入れ子の部分を奇妙に感じるかも知れませんが、
cmd
は、/c
の次の引数が"
で始まると、以降の全てを対象に最初と最後の"
を外すだけらしいです。
スリープ前にNoteする
Nyahn&SleepComputer.bat
echo off
chcp 65001
start /wait /min cmd /C "chcp 65001&%~dp0note.bat "にゃ~ん🐈💤""
timeout /NOBREAK /T 10
powershell -WindowStyle Hidden -Command "Add-Type -Assembly System.Windows.Forms;[System.Windows.Forms.Application]::SetSuspendState('Suspend', $false, $false);"
一時ファイルを抹消する
- ここで、前述の懸念を払拭するために、以下の1行を加えます。
Nyahn&SleepComputer.bat
~
timeout /NOBREAK /T 10
+ del %TEMP%\note.json
Windows Update で発火しないように
- イベントの起因をUSBデバイスや電源スイッチに限定します。
- タスクスケジューラのトリガーの編集で設定をカスタムにして、イベントフィルタをXMLに切り替え、手動でクエリを編集します。
<QueryList>
<Query Id="0" Path="System">
<Select Path="System">
*[System[Provider[@Name="Microsoft-Windows-Power-Troubleshooter"] and (EventID='1')]]
and
*[EventData[(Data[@Name='WakeSourceType']='1' or Data[@Name='WakeSourceType']='5')]]
</Select>
</Query>
</QueryList>
-
Troubleshooter
とEventID='1'
が、元のままの基本的な条件です。 -
WakeSourceType
の1
が電源スイッチ、USBデバイスだと5
です。- ネットワークアダプタなど、USB以外でも
5
の場合があるので、(Data[@Name='WakeSourceType']='5' and Data[@Name='WakeSourceTextLength']='xx')
などとして、デバイス名を絞り込む必要があるかも知れません。
- ネットワークアダプタなど、USB以外でも