Feat: カスタム絵文字チェック機能 (#127)

* カスタム絵文字チェックモジュールの追加

* カスタム絵文字チェックモジュールの修正

- README.mdやtorisetu.mdに記載
- カスタム絵文字投稿をまとめる設定を追加(checkEmojisAtOnce)
This commit is contained in:
tetsuya-ki 2024-01-08 14:50:46 +09:00 committed by GitHub
parent 341b0eadb4
commit 296b63c6cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 181 additions and 0 deletions

View file

@ -19,6 +19,8 @@ Misskey用の日本語Botです。
"chartEnabled": "チャート機能を無効化する場合は false を入れてください", "chartEnabled": "チャート機能を無効化する場合は false を入れてください",
"reversiEnabled": "藍とリバーシで対局できる機能を有効にする場合は true を入れる (無効にする場合は false)", "reversiEnabled": "藍とリバーシで対局できる機能を有効にする場合は true を入れる (無効にする場合は false)",
"serverMonitoring": "サーバー監視の機能を有効にする場合は true を入れる (無効にする場合は false)", "serverMonitoring": "サーバー監視の機能を有効にする場合は true を入れる (無効にする場合は false)",
"checkEmojisEnabled": "カスタム絵文字チェック機能を有効にする場合は true を入れる (無効にする場合は false)",
"checkEmojisAtOnce": "カスタム絵文字チェック機能で投稿をまとめる場合は true を入れる (まとめない場合は false)",
"mecab": "MeCab のインストールパス (ソースからインストールした場合、大体は /usr/local/bin/mecab)", "mecab": "MeCab のインストールパス (ソースからインストールした場合、大体は /usr/local/bin/mecab)",
"mecabDic": "MeCab の辞書ファイルパス (オプション)", "mecabDic": "MeCab の辞書ファイルパス (オプション)",
"memoryDir": "memory.jsonの保存先オプション、デフォルトは'.'(レポジトリのルートです))" "memoryDir": "memory.jsonの保存先オプション、デフォルトは'.'(レポジトリのルートです))"
@ -40,6 +42,8 @@ Misskey用の日本語Botです。
"chartEnabled": "チャート機能を無効化する場合は false を入れてください", "chartEnabled": "チャート機能を無効化する場合は false を入れてください",
"reversiEnabled": "藍とリバーシで対局できる機能を有効にする場合は true を入れる (無効にする場合は false)", "reversiEnabled": "藍とリバーシで対局できる機能を有効にする場合は true を入れる (無効にする場合は false)",
"serverMonitoring": "サーバー監視の機能を有効にする場合は true を入れる (無効にする場合は false)", "serverMonitoring": "サーバー監視の機能を有効にする場合は true を入れる (無効にする場合は false)",
"checkEmojisEnabled": "カスタム絵文字チェック機能を有効にする場合は true を入れる (無効にする場合は false)",
"checkEmojisAtOnce": "カスタム絵文字チェック機能で投稿をまとめる場合は true を入れる (まとめない場合は false)",
"mecab": "/usr/bin/mecab", "mecab": "/usr/bin/mecab",
"mecabDic": "/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd/", "mecabDic": "/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd/",
"memoryDir": "data" "memoryDir": "data"

View file

@ -1,5 +1,6 @@
type Config = { type Config = {
host: string; host: string;
serverName?: string;
i: string; i: string;
master?: string; master?: string;
wsUrl: string; wsUrl: string;
@ -9,6 +10,8 @@ type Config = {
notingEnabled: boolean; notingEnabled: boolean;
chartEnabled: boolean; chartEnabled: boolean;
serverMonitoring: boolean; serverMonitoring: boolean;
checkEmojisEnabled?: boolean;
checkEmojisAtOnce?: boolean;
mecab?: string; mecab?: string;
mecabDic?: string; mecabDic?: string;
memoryDir?: string; memoryDir?: string;

View file

@ -34,6 +34,7 @@ import SleepReportModule from './modules/sleep-report';
import NotingModule from './modules/noting'; import NotingModule from './modules/noting';
import PollModule from './modules/poll'; import PollModule from './modules/poll';
import ReminderModule from './modules/reminder'; import ReminderModule from './modules/reminder';
import CheckCustomEmojisModule from './modules/check-custom-emojis';
console.log(' __ ____ _____ ___ '); console.log(' __ ____ _____ ___ ');
console.log(' /__\\ (_ _)( _ )/ __)'); console.log(' /__\\ (_ _)( _ )/ __)');
@ -88,6 +89,7 @@ promiseRetry(retry => {
new NotingModule(), new NotingModule(),
new PollModule(), new PollModule(),
new ReminderModule(), new ReminderModule(),
new CheckCustomEmojisModule(),
]); ]);
}).catch(e => { }).catch(e => {
log(chalk.red('Failed to fetch the account')); log(chalk.red('Failed to fetch the account'));

View file

@ -0,0 +1,162 @@
import autobind from 'autobind-decorator';
import * as loki from 'lokijs';
import Module from '@/module';
import serifs from '@/serifs';
import config from '@/config';
import Message from '@/message';
export default class extends Module {
public readonly name = 'checkCustomEmojis';
private lastEmoji: loki.Collection<{
id: string;
updatedAt: number;
}>;
@autobind
public install() {
if (!config.checkEmojisEnabled) return {};
this.lastEmoji = this.ai.getCollection('lastEmoji', {
indices: ['id']
});
this.timeCheck();
setInterval(this.timeCheck, 1000 * 60 * 3);
return {
mentionHook: this.mentionHook
};
}
@autobind
private timeCheck() {
const now = new Date();
if (now.getHours() !== 23) return;
const date = `${now.getFullYear()}-${now.getMonth()}-${now.getDate()}`;
const data = this.getData();
if (data.lastPosted == date) return;
data.lastPosted = date;
this.setData(data);
this.log('Time to Check CustomEmojis!');
this.post();
}
@autobind
private async post() {
this.log('Start to Check CustomEmojis.');
const lastEmoji = this.lastEmoji.find({});
const lastId = lastEmoji.length != 0 ? lastEmoji[0].id : null;
const emojisData = await this.checkCumstomEmojis(lastId);
if (emojisData.length == 0) {
this.log('No CustomEmojis Added.');
return;
}
// 絵文字データが取得された場合、元々のデータを削除しておく
const emojiSize = emojisData.length;
this.lastEmoji.remove(lastEmoji);
const server_name = config.serverName ? config.serverName : 'このサーバー';
this.log('Posting...');
// 一気に投稿しないver
if (!config.checkEmojisAtOnce){
// 概要について投稿
this.log(serifs.checkCustomEmojis.post(server_name, emojiSize));
await this.ai.post({
text: serifs.checkCustomEmojis.post(server_name, emojiSize)
});
// 各絵文字について投稿
for (const emoji of emojisData){
await this.ai.post({
text: serifs.checkCustomEmojis.emojiPost(emoji.name)
});
this.log(serifs.checkCustomEmojis.emojiPost(emoji.name));
}
} else {
// 一気に投稿ver
let text = '';
for (const emoji of emojisData){
text += serifs.checkCustomEmojis.emojiOnce(emoji.name);
}
const message = serifs.checkCustomEmojis.postOnce(server_name, emojiSize, text);
this.log(message);
await this.ai.post({
text: message
});
}
// データの保存
this.log('Last CustomEmojis data saving...');
this.log(JSON.stringify(emojisData[emojiSize-1],null,'\t'));
this.lastEmoji.insertOne({
id: emojisData[emojiSize-1].id,
updatedAt: Date.now()
});
this.log('Check CustomEmojis finished!');
}
@autobind
private async checkCumstomEmojis(lastId : any) {
this.log('CustomEmojis fetching...');
let emojisData;
if(lastId != null){
this.log('lastId is **not** null');
emojisData = await this.ai.api('admin/emoji/list', {
sinceId: lastId,
limit: 30
});
} else {
this.log('lastId is null');
emojisData = await this.ai.api('admin/emoji/list', {
limit: 100
});
// 最後まで取得
let beforeEmoji = null;
let afterEmoji = emojisData.length > 1 ? emojisData[0] : null;
while(emojisData.length == 100 && beforeEmoji != afterEmoji){
const lastId = emojisData[emojisData.length-1].id;
// sinceIdを指定して再度取り直す
emojisData = await this.ai.api('admin/emoji/list', {
limit: 100,
sinceId: lastId
});
beforeEmoji = afterEmoji;
afterEmoji = emojisData.length > 1 ? emojisData[0] : null;
await this.sleep(50);
}
// sinceIdが未指定の場合、末尾から5件程度にしておく
let newJson: any[] = [];
for (let i = emojisData.length - 5; i < emojisData.length; i++) {
newJson.push(emojisData[i]);
}
emojisData = newJson;
}
return emojisData;
}
@autobind
private async mentionHook(msg: Message) {
if (!msg.includes(['カスタムえもじチェック','カスタムえもじを調べて','カスタムえもじを確認'])) {
return false;
} else {
this.log('Check CustomEmojis requested');
}
await this.post();
return {
reaction: 'like'
};
}
@autobind
private async sleep(ms: number) {
return new Promise((res) => setTimeout(res, ms));
}
}

View file

@ -381,6 +381,13 @@ export default {
foryou: '描きました!' foryou: '描きました!'
}, },
checkCustomEmojis: {
post: (server_name, num) => `${server_name}${num}件の絵文字が追加されました!`,
emojiPost: emoji => `:${emoji}:\n(\`${emoji}\`) #AddCustomEmojis`,
postOnce: (server_name, num, text) => `${server_name}${num}件の絵文字が追加されました!\n${text} #AddCustomEmojis`,
emojiOnce: emoji => `:${emoji}:(\`${emoji}\`)`
},
sleepReport: { sleepReport: {
report: hours => `んぅ、${hours}時間くらい寝ちゃってたみたいです`, report: hours => `んぅ、${hours}時間くらい寝ちゃってたみたいです`,
reportUtatane: 'ん... うたた寝しちゃってました', reportUtatane: 'ん... うたた寝しちゃってました',

View file

@ -75,6 +75,9 @@ Misskeyにアカウントを作成して初めて投稿を行うと、藍がネ
### ping ### ping
PONGを返します。生存確認にどうぞ PONGを返します。生存確認にどうぞ
### カスタム絵文字チェック
1日に1回、カスタム絵文字の追加を監視してくれます。「カスタムえもじチェック」または「カスタムえもじを確認して」ですぐに確認してくれます。
### その他反応するフレーズ (トークのみ) ### その他反応するフレーズ (トークのみ)
* かわいい * かわいい
* なでなで * なでなで