Add ESLint

This commit is contained in:
na2na-p 2022-08-10 16:58:29 +09:00
parent 98f22f2b9d
commit 71c73de59e
No known key found for this signature in database
GPG key ID: 188940C4AA4A067E
57 changed files with 6442 additions and 739 deletions

29
.eslintrc.js Normal file
View file

@ -0,0 +1,29 @@
module.exports = {
'env': {
'es2021': true,
'node': true,
},
'extends': [
'google',
],
'parser': '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 'latest',
'sourceType': 'module',
},
'plugins': [
'@typescript-eslint',
],
'rules': {
'no-tabs': 'off',
'max-len': ['error', {'code': 120}],
'indent': ['error', 'tab'],
'@typescript-eslint/no-unused-vars': ['warn', {'argsIgnorePattern': '^_'}],
'no-unused-vars': 'off',
'require-jsdoc': 'off',
'valid-jsdoc': 'off',
'max-len': 'off',
'no-mixed-spaces-and-tabs': 'off',
'new-cap': 'off',
},
};

19
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,19 @@
name: CI
on:
push:
branches-ignore:
- main
jobs:
ESLint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 18.x
- name: ci
run: yarn install --immutable --immutable-cache --check-cache
- name: ESLint
run: yarn lint

View file

@ -4,7 +4,9 @@
"scripts": { "scripts": {
"start": "node ./built", "start": "node ./built",
"build": "tsc", "build": "tsc",
"test": "jest" "test": "jest",
"lint": "yarn eslint --ext .js,.ts .",
"lint:fix": "yarn eslint --ext .js,.ts . --fix"
}, },
"dependencies": { "dependencies": {
"@types/chalk": "2.2.0", "@types/chalk": "2.2.0",
@ -47,6 +49,10 @@
"@types/koa__router": "8.0.11", "@types/koa__router": "8.0.11",
"@types/node-fetch": "3.0.3", "@types/node-fetch": "3.0.3",
"@types/websocket": "1.0.5", "@types/websocket": "1.0.5",
"@typescript-eslint/eslint-plugin": "5.33.0",
"@typescript-eslint/parser": "5.33.0",
"eslint": ">=5.16.0",
"eslint-config-google": "0.14.0",
"jest": "26.6.3", "jest": "26.6.3",
"koa": "2.13.4", "koa": "2.13.4",
"koa-json-body": "5.3.0", "koa-json-body": "5.3.0",

View file

@ -114,14 +114,14 @@ export default class 藍 {
autoload: true, autoload: true,
autosave: true, autosave: true,
autosaveInterval: 1000, autosaveInterval: 1000,
autoloadCallback: err => { autoloadCallback: (err) => {
if (err) { if (err) {
this.log(chalk.red(`Failed to load the memory: ${err}`)); this.log(chalk.red(`Failed to load the memory: ${err}`));
} else { } else {
this.log(chalk.green('The memory loaded successfully')); this.log(chalk.green('The memory loaded successfully'));
this.run(); this.run();
} }
} },
}); });
} }
@ -136,19 +136,19 @@ export default class 藍 {
this.meta = this.getCollection('meta', {}); this.meta = this.getCollection('meta', {});
this.contexts = this.getCollection('contexts', { this.contexts = this.getCollection('contexts', {
indices: ['key'] indices: ['key'],
}); });
this.timers = this.getCollection('timers', { this.timers = this.getCollection('timers', {
indices: ['module'] indices: ['module'],
}); });
this.friends = this.getCollection('friends', { this.friends = this.getCollection('friends', {
indices: ['userId'] indices: ['userId'],
}); });
this.moduleData = this.getCollection('moduleData', { this.moduleData = this.getCollection('moduleData', {
indices: ['module'] indices: ['module'],
}); });
// #endregion // #endregion
@ -162,7 +162,7 @@ export default class 藍 {
const mainStream = this.connection.useSharedConnection('main'); const mainStream = this.connection.useSharedConnection('main');
// メンションされたとき // メンションされたとき
mainStream.on('mention', async data => { mainStream.on('mention', async (data) => {
if (data.userId == this.account.id) return; // 自分は弾く if (data.userId == this.account.id) return; // 自分は弾く
if (data.text && data.text.startsWith('@' + this.account.username)) { if (data.text && data.text.startsWith('@' + this.account.username)) {
// Misskeyのバグで投稿が非公開扱いになる // Misskeyのバグで投稿が非公開扱いになる
@ -172,7 +172,7 @@ export default class 藍 {
}); });
// 返信されたとき // 返信されたとき
mainStream.on('reply', async data => { mainStream.on('reply', async (data) => {
if (data.userId == this.account.id) return; // 自分は弾く if (data.userId == this.account.id) return; // 自分は弾く
if (data.text && data.text.startsWith('@' + this.account.username)) return; if (data.text && data.text.startsWith('@' + this.account.username)) return;
// Misskeyのバグで投稿が非公開扱いになる // Misskeyのバグで投稿が非公開扱いになる
@ -181,31 +181,31 @@ export default class 藍 {
}); });
// Renoteされたとき // Renoteされたとき
mainStream.on('renote', async data => { mainStream.on('renote', async (data) => {
if (data.userId == this.account.id) return; // 自分は弾く if (data.userId == this.account.id) return; // 自分は弾く
if (data.text == null && (data.files || []).length == 0) return; if (data.text == null && (data.files || []).length == 0) return;
// リアクションする // リアクションする
this.api('notes/reactions/create', { this.api('notes/reactions/create', {
noteId: data.id, noteId: data.id,
reaction: 'love' reaction: 'love',
}); });
}); });
// メッセージ // メッセージ
mainStream.on('messagingMessage', data => { mainStream.on('messagingMessage', (data) => {
if (data.userId == this.account.id) return; // 自分は弾く if (data.userId == this.account.id) return; // 自分は弾く
this.onReceiveMessage(new Message(this, data, true)); this.onReceiveMessage(new Message(this, data, true));
}); });
// 通知 // 通知
mainStream.on('notification', data => { mainStream.on('notification', (data) => {
this.onNotification(data); this.onNotification(data);
}); });
// #endregion // #endregion
// Install modules // Install modules
this.modules.forEach(m => { this.modules.forEach((m) => {
this.log(`Installing ${chalk.cyan.italic(m.name)}\tmodule...`); this.log(`Installing ${chalk.cyan.italic(m.name)}\tmodule...`);
m.init(this); m.init(this);
const res = m.install(); const res = m.install();
@ -244,10 +244,10 @@ export default class 藍 {
// Look up the context // Look up the context
const context = isNoContext ? null : this.contexts.findOne(msg.isDm ? { const context = isNoContext ? null : this.contexts.findOne(msg.isDm ? {
isDm: true, isDm: true,
userId: msg.userId userId: msg.userId,
} : { } : {
isDm: false, isDm: false,
noteId: msg.replyId noteId: msg.replyId,
}); });
let reaction: string | null = 'love'; let reaction: string | null = 'love';
@ -301,7 +301,7 @@ export default class 藍 {
if (reaction) { if (reaction) {
this.api('notes/reactions/create', { this.api('notes/reactions/create', {
noteId: msg.id, noteId: msg.id,
reaction: reaction reaction: reaction,
}); });
} }
} }
@ -362,7 +362,7 @@ export default class 藍 {
@autobind @autobind
public lookupFriend(userId: User['id']): Friend | null { public lookupFriend(userId: User['id']): Friend | null {
const doc = this.friends.findOne({ const doc = this.friends.findOne({
userId: userId userId: userId,
}); });
if (doc == null) return null; if (doc == null) return null;
@ -383,10 +383,10 @@ export default class 藍 {
i: config.i, i: config.i,
file: { file: {
value: file, value: file,
options: meta options: meta,
}
}, },
json: true },
json: true,
}); });
return res; return res;
} }
@ -417,8 +417,8 @@ export default class 藍 {
public api(endpoint: string, param?: any) { public api(endpoint: string, param?: any) {
return request.post(`${config.apiUrl}/${endpoint}`, { return request.post(`${config.apiUrl}/${endpoint}`, {
json: Object.assign({ json: Object.assign({
i: config.i i: config.i,
}, param) }, param),
}); });
}; };
@ -437,13 +437,13 @@ export default class 藍 {
userId: id, userId: id,
module: module.name, module: module.name,
key: key, key: key,
data: data data: data,
} : { } : {
isDm: false, isDm: false,
noteId: id, noteId: id,
module: module.name, module: module.name,
key: key, key: key,
data: data data: data,
}); });
} }
@ -456,7 +456,7 @@ export default class 藍 {
public unsubscribeReply(module: Module, key: string | null) { public unsubscribeReply(module: Module, key: string | null) {
this.contexts.findAndRemove({ this.contexts.findAndRemove({
key: key, key: key,
module: module.name module: module.name,
}); });
} }
@ -475,7 +475,7 @@ export default class 藍 {
module: module.name, module: module.name,
insertedAt: Date.now(), insertedAt: Date.now(),
delay: delay, delay: delay,
data: data data: data,
}); });
this.log(`Timer persisted: ${module.name} ${id} ${delay}ms`); this.log(`Timer persisted: ${module.name} ${id} ${delay}ms`);

View file

@ -43,13 +43,13 @@ export default class Friend {
if (opts.user) { if (opts.user) {
const exist = this.ai.friends.findOne({ const exist = this.ai.friends.findOne({
userId: opts.user.id userId: opts.user.id,
}); });
if (exist == null) { if (exist == null) {
const inserted = this.ai.friends.insertOne({ const inserted = this.ai.friends.insertOne({
userId: opts.user.id, userId: opts.user.id,
user: opts.user user: opts.user,
}); });
if (inserted == null) { if (inserted == null) {
@ -172,7 +172,7 @@ export default class Friend {
@autobind @autobind
public transferMemory(code: string): boolean { public transferMemory(code: string): boolean {
const src = this.ai.friends.findOne({ const src = this.ai.friends.findOne({
transferCode: code transferCode: code,
}); });
if (src == null) return false; if (src == null) return false;

View file

@ -15,7 +15,7 @@ import CoreModule from './modules/core';
import TalkModule from './modules/talk'; import TalkModule from './modules/talk';
import BirthdayModule from './modules/birthday'; import BirthdayModule from './modules/birthday';
import ReversiModule from './modules/reversi'; import ReversiModule from './modules/reversi';
import summonCat from './modules/summonCat'; import SummonCat from './modules/summonCat';
import PingModule from './modules/ping'; import PingModule from './modules/ping';
import EmojiModule from './modules/emoji'; import EmojiModule from './modules/emoji';
import EmojiReactModule from './modules/emoji-react'; import EmojiReactModule from './modules/emoji-react';
@ -35,9 +35,9 @@ 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 earthquake from './modules/earthquake'; import Earthquake from './modules/earthquake';
import DicModule from './modules/dic'; import DicModule from './modules/dic';
import menuModule from './modules/menu'; import MenuModule from './modules/menu';
import GetColorModule from './modules/color'; import GetColorModule from './modules/color';
console.log(' __ ____ _____ ___ '); console.log(' __ ____ _____ ___ ');
@ -51,18 +51,18 @@ function log(msg: string): void {
log(chalk.bold(`Ai v${pkg._v}`)); log(chalk.bold(`Ai v${pkg._v}`));
promiseRetry(retry => { promiseRetry((retry) => {
log(`Account fetching... ${chalk.gray(config.host)}`); log(`Account fetching... ${chalk.gray(config.host)}`);
// アカウントをフェッチ // アカウントをフェッチ
return request.post(`${config.apiUrl}/i`, { return request.post(`${config.apiUrl}/i`, {
json: { json: {
i: config.i i: config.i,
} },
}).catch(retry); }).catch(retry);
}, { }, {
retries: 3 retries: 3,
}).then(account => { }).then((account) => {
const acct = `@${account.username}`; const acct = `@${account.username}`;
log(chalk.green(`Account fetched successfully: ${chalk.underline(acct)}`)); log(chalk.green(`Account fetched successfully: ${chalk.underline(acct)}`));
@ -72,7 +72,7 @@ promiseRetry(retry => {
new (account, [ new (account, [
new CoreModule(), new CoreModule(),
new ReminderModule(), new ReminderModule(),
new summonCat(), new SummonCat(),
new EmojiModule(), new EmojiModule(),
new EmojiReactModule(), new EmojiReactModule(),
new FortuneModule(), new FortuneModule(),
@ -95,10 +95,10 @@ promiseRetry(retry => {
new NotingModule(), new NotingModule(),
// new PollModule(), // new PollModule(),
new DicModule(), new DicModule(),
new menuModule(), new MenuModule(),
new GetColorModule(), new GetColorModule(),
new earthquake(), new Earthquake(),
]); ]);
}).catch(e => { }).catch((e) => {
log(chalk.red('Failed to fetch the account')); log(chalk.red('Failed to fetch the account'));
}); });

View file

@ -64,8 +64,8 @@ export default class Message {
// メッセージなどに付いているユーザー情報は省略されている場合があるので完全なユーザー情報を持ってくる // メッセージなどに付いているユーザー情報は省略されている場合があるので完全なユーザー情報を持ってくる
this.ai.api('users/show', { this.ai.api('users/show', {
userId: this.userId userId: this.userId,
}).then(user => { }).then((user) => {
this.friend.updateUser(user); this.friend.updateUser(user);
}); });
} }
@ -88,7 +88,7 @@ export default class Message {
if (this.isDm) { if (this.isDm) {
return await this.ai.sendMessage(this.messageOrNote.userId, { return await this.ai.sendMessage(this.messageOrNote.userId, {
text: text, text: text,
fileId: opts?.file?.id fileId: opts?.file?.id,
}); });
} else { } else {
return await this.ai.post({ return await this.ai.post({
@ -96,7 +96,7 @@ export default class Message {
text: text, text: text,
fileIds: opts?.file ? [opts?.file.id] : undefined, fileIds: opts?.file ? [opts?.file.id] : undefined,
cw: opts?.cw, cw: opts?.cw,
renoteId: opts?.renote renoteId: opts?.renote,
}); });
} }
} }

View file

@ -7,7 +7,7 @@ export type Note = {
}, },
text: string | null; text: string | null;
cw: string | null; cw: string | null;
visibility: "public" | "home" | "followers" | "specified"; visibility: 'public' | 'home' | 'followers' | 'specified';
reply: any | null; reply: any | null;
poll?: { poll?: {
choices: { choices: {

View file

@ -11,13 +11,13 @@ export default abstract class Module {
this.ai = ai; this.ai = ai;
this.doc = this.ai.moduleData.findOne({ this.doc = this.ai.moduleData.findOne({
module: this.name module: this.name,
}); });
if (this.doc == null) { if (this.doc == null) {
this.doc = this.ai.moduleData.insertOne({ this.doc = this.ai.moduleData.insertOne({
module: this.name, module: this.name,
data: {} data: {},
}); });
} }
} }

View file

@ -30,10 +30,10 @@ export default class extends Module {
const today = `${zeroPadding(m + 1, 2)}-${zeroPadding(d, 2)}`; const today = `${zeroPadding(m + 1, 2)}-${zeroPadding(d, 2)}`;
const birthFriends = this.ai.friends.find({ const birthFriends = this.ai.friends.find({
'user.birthday': { '$regex': new RegExp('-' + today + '$') } 'user.birthday': {'$regex': new RegExp('-' + today + '$')},
} as any); } as any);
birthFriends.forEach(f => { birthFriends.forEach((f) => {
const friend = new Friend(this.ai, {doc: f}); const friend = new Friend(this.ai, {doc: f});
// 親愛度が3以上必要 // 親愛度が3以上必要
@ -49,7 +49,7 @@ export default class extends Module {
const text = serifs.birthday.happyBirthday(friend.name); const text = serifs.birthday.happyBirthday(friend.name);
this.ai.sendMessage(friend.userId, { this.ai.sendMessage(friend.userId, {
text: text text: text,
}); });
}); });
} }

View file

@ -18,7 +18,7 @@ export default class extends Module {
setInterval(this.post, 1000 * 60 * 3); setInterval(this.post, 1000 * 60 * 3);
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -38,7 +38,7 @@ export default class extends Module {
this.log('Posting...'); this.log('Posting...');
this.ai.post({ this.ai.post({
text: serifs.chart.post, text: serifs.chart.post,
fileIds: [file.id] fileIds: [file.id],
}); });
} }
@ -52,33 +52,33 @@ export default class extends Module {
const data = await this.ai.api('charts/user/notes', { const data = await this.ai.api('charts/user/notes', {
span: 'day', span: 'day',
limit: 30, limit: 30,
userId: params.user.id userId: params.user.id,
}); });
chart = { chart = {
title: `@${params.user.username}さんの投稿数`, title: `@${params.user.username}さんの投稿数`,
datasets: [{ datasets: [{
data: data.diffs.normal data: data.diffs.normal,
}, { }, {
data: data.diffs.reply data: data.diffs.reply,
}, { }, {
data: data.diffs.renote data: data.diffs.renote,
}] }],
}; };
} else if (type === 'followers') { } else if (type === 'followers') {
const data = await this.ai.api('charts/user/following', { const data = await this.ai.api('charts/user/following', {
span: 'day', span: 'day',
limit: 30, limit: 30,
userId: params.user.id userId: params.user.id,
}); });
chart = { chart = {
title: `@${params.user.username}さんのフォロワー数`, title: `@${params.user.username}さんのフォロワー数`,
datasets: [{ datasets: [{
data: data.local.followers.total data: data.local.followers.total,
}, { }, {
data: data.remote.followers.total data: data.remote.followers.total,
}] }],
}; };
} else if (type === 'notes') { } else if (type === 'notes') {
const data = await this.ai.api('charts/notes', { const data = await this.ai.api('charts/notes', {
@ -88,12 +88,12 @@ export default class extends Module {
chart = { chart = {
datasets: [{ datasets: [{
data: data.local.diffs.normal data: data.local.diffs.normal,
}, { }, {
data: data.local.diffs.reply data: data.local.diffs.reply,
}, { }, {
data: data.local.diffs.renote data: data.local.diffs.renote,
}] }],
}; };
} else { } else {
const suffixes = ['の売り上げ', 'の消費', 'の生産']; const suffixes = ['の売り上げ', 'の消費', 'の生産'];
@ -102,10 +102,10 @@ export default class extends Module {
const diffRange = 150; const diffRange = 150;
const datasetCount = 1 + Math.floor(Math.random() * 3); const datasetCount = 1 + Math.floor(Math.random() * 3);
let datasets: any[] = []; const datasets: any[] = [];
for (let d = 0; d < datasetCount; d++) { for (let d = 0; d < datasetCount; d++) {
let values = [Math.random() * 1000]; const values = [Math.random() * 1000];
for (let i = 1; i < limit; i++) { for (let i = 1; i < limit; i++) {
const prev = values[i - 1]; const prev = values[i - 1];
@ -113,13 +113,13 @@ export default class extends Module {
} }
datasets.push({ datasets.push({
data: values data: values,
}); });
} }
chart = { chart = {
title: items[Math.floor(Math.random() * items.length)] + suffixes[Math.floor(Math.random() * suffixes.length)], title: items[Math.floor(Math.random() * items.length)] + suffixes[Math.floor(Math.random() * suffixes.length)],
datasets: datasets datasets: datasets,
}; };
} }
@ -129,7 +129,7 @@ export default class extends Module {
this.log('Image uploading...'); this.log('Image uploading...');
const file = await this.ai.upload(img, { const file = await this.ai.upload(img, {
filename: 'chart.png', filename: 'chart.png',
contentType: 'image/png' contentType: 'image/png',
}); });
return file; return file;
@ -148,14 +148,14 @@ export default class extends Module {
if (msg.includes(['投稿'])) type = 'userNotes'; if (msg.includes(['投稿'])) type = 'userNotes';
const file = await this.genChart(type, { const file = await this.genChart(type, {
user: msg.user user: msg.user,
}); });
this.log('Replying...'); this.log('Replying...');
msg.reply(serifs.chart.foryou, {file}); msg.reply(serifs.chart.foryou, {file});
return { return {
reaction: 'like' reaction: 'like',
}; };
} }
} }

View file

@ -18,7 +18,7 @@ const colors = {
'#69d2e7', '#69d2e7',
'#f38630', '#f38630',
'#f9d423', '#f9d423',
] ],
}; };
const yAxisTicks = 4; const yAxisTicks = 4;
@ -42,9 +42,9 @@ export function renderChart(chart: Chart) {
ctx.beginPath(); ctx.beginPath();
ctx.fillRect(0, 0, width, height); ctx.fillRect(0, 0, width, height);
let chartAreaX = margin; const chartAreaX = margin;
let chartAreaY = margin; let chartAreaY = margin;
let chartAreaWidth = width - (margin * 2); const chartAreaWidth = width - (margin * 2);
let chartAreaHeight = height - (margin * 2); let chartAreaHeight = height - (margin * 2);
// Draw title // Draw title
@ -100,7 +100,7 @@ export function renderChart(chart: Chart) {
for (let series = 0; series < serieses; series++) { for (let series = 0; series < serieses; series++) {
newDatasets.push({ newDatasets.push({
data: [] data: [],
}); });
} }

View file

@ -9,7 +9,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -22,7 +22,7 @@ export default class extends Module {
const b = Math.floor(Math.random() * 256); const b = Math.floor(Math.random() * 256);
// rgbをhexに変換する // rgbをhexに変換する
const hex = `${r.toString(16)}${g.toString(16)}${b.toString(16)}`; const hex = `${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
const message = `RGB: ${r}, ${g}, ${b} \`(#${hex})\`とかどう?` const message = `RGB: ${r}, ${g}, ${b} \`(#${hex})\`とかどう?`;
setTimeout(async () => { setTimeout(async () => {
const file = await this.getColorSampleFile(r, g, b); const file = await this.getColorSampleFile(r, g, b);
@ -30,7 +30,7 @@ export default class extends Module {
msg.reply(message, {file}); msg.reply(message, {file});
}, 500); }, 500);
return { return {
reaction: '🎨' reaction: '🎨',
}; };
} else { } else {
return false; return false;
@ -44,7 +44,7 @@ export default class extends Module {
this.log('Image uploading...'); this.log('Image uploading...');
const file = await this.ai.upload(colorSample, { const file = await this.ai.upload(colorSample, {
filename: 'color.png', filename: 'color.png',
contentType: 'image/png' contentType: 'image/png',
}); });
return file; return file;

View file

@ -13,7 +13,7 @@ export default class extends Module {
public install() { public install() {
return { return {
mentionHook: this.mentionHook, mentionHook: this.mentionHook,
contextHook: this.contextHook contextHook: this.contextHook,
}; };
} }
@ -87,15 +87,15 @@ export default class extends Module {
return true; return true;
} }
const withSan = titles.some(t => name.endsWith(t)); const withSan = titles.some((t) => name.endsWith(t));
if (withSan) { if (withSan) {
msg.friend.updateName(name); msg.friend.updateName(name);
msg.reply(serifs.core.setNameOk(name)); msg.reply(serifs.core.setNameOk(name));
} else { } else {
msg.reply(serifs.core.san).then(reply => { msg.reply(serifs.core.san).then((reply) => {
this.subscribeReply(msg.userId, msg.isDm, msg.isDm ? msg.userId : reply.id, { this.subscribeReply(msg.userId, msg.isDm, msg.isDm ? msg.userId : reply.id, {
name: name name: name,
}); });
}); });
} }
@ -117,7 +117,7 @@ export default class extends Module {
text += '```'; text += '```';
msg.reply(text, { msg.reply(text, {
immediate: true immediate: true,
}); });
return true; return true;
@ -129,7 +129,7 @@ export default class extends Module {
if (!msg.or(['v', 'version', 'バージョン'])) return false; if (!msg.or(['v', 'version', 'バージョン'])) return false;
msg.reply(`\`\`\`\nv${this.ai.version}\n\`\`\``, { msg.reply(`\`\`\`\nv${this.ai.version}\n\`\`\``, {
immediate: true immediate: true,
}); });
return true; return true;
@ -151,7 +151,7 @@ export default class extends Module {
msg.friend.updateName(data.name); msg.friend.updateName(data.name);
done(); done();
} else { } else {
msg.reply(serifs.core.yesOrNo).then(reply => { msg.reply(serifs.core.yesOrNo).then((reply) => {
this.subscribeReply(msg.userId, msg.isDm, reply.id, data); this.subscribeReply(msg.userId, msg.isDm, reply.id, data);
}); });
} }

View file

@ -8,7 +8,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -16,13 +16,13 @@ export default class extends Module {
private async mentionHook(msg: Message) { private async mentionHook(msg: Message) {
if (msg.text && msg.text.includes('って何')) { if (msg.text && msg.text.includes('って何')) {
// msg.textのうち、「の意味は」の直前で、「@ai」よりも後の物を抽出 // msg.textのうち、「の意味は」の直前で、「@ai」よりも後の物を抽出
const dic_prefix = "https://www.weblio.jp/content/"; const dicPrefix = 'https://www.weblio.jp/content/';
const raw_word = msg.text.split('って何')[0].split('@ai')[1].trim(); const rawWord = msg.text.split('って何')[0].split('@ai')[1].trim();
// スペースがある場合は、半角スペースを除去 // スペースがある場合は、半角スペースを除去
const word = raw_word.replace(/\s/g, ''); const word = rawWord.replace(/\s/g, '');
const url = dic_prefix + encodeURIComponent(word); const url = dicPrefix + encodeURIComponent(word);
msg.reply(`こんな意味っぽい?> [${word}](${url})`, { msg.reply(`こんな意味っぽい?> [${word}](${url})`, {
immediate: true immediate: true,
}); });
return true; return true;
} else { } else {

View file

@ -9,7 +9,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }

View file

@ -1,13 +1,13 @@
import autobind from "autobind-decorator"; import autobind from 'autobind-decorator';
import Module from "@/module"; import Module from '@/module';
import config from "@/config"; import config from '@/config';
import Message from "@/message"; import Message from '@/message';
import * as http from "http"; import * as http from 'http';
// 基本的に生データはstringばっかり。都合のいい形に加工済みの状態の型定義を書いています。 // 基本的に生データはstringばっかり。都合のいい形に加工済みの状態の型定義を書いています。
// ここでいくらか言及されてる(https://bultar.bbs.fc2.com/?act=reply&tid=5645851); // ここでいくらか言及されてる(https://bultar.bbs.fc2.com/?act=reply&tid=5645851);
interface { interface {
type: "eew"; type: 'eew';
time: Date; time: Date;
report: string; // 第n報 最終報はstringで'final'となるので、とりあえずstring型 report: string; // 第n報 最終報はstringで'final'となるので、とりあえずstring型
epicenter: string; // 震源地 epicenter: string; // 震源地
@ -20,12 +20,12 @@ interface 緊急地震速報 {
} }
interface { interface {
type: "pga_alert_cancel"; type: 'pga_alert_cancel';
time: Date; time: Date;
} }
interface { interface {
type: "intensity_report"; type: 'intensity_report';
time: string; time: string;
max_index: number; max_index: number;
intensity_list: { intensity_list: {
@ -36,7 +36,7 @@ interface 震度レポート {
} }
interface { interface {
type: "pga_alert"; type: 'pga_alert';
time: Date; time: Date;
max_pga: number; max_pga: number;
new: boolean; new: boolean;
@ -45,22 +45,22 @@ interface 地震検知 {
} }
export default class extends Module { export default class extends Module {
public readonly name = "earthquake"; public readonly name = 'earthquake';
private message: string = ""; private message: string = '';
private thresholdVal = 3; // 下の配列の添え字に相当する値。しきい値以上のものについて通知を出す。 普段は3(震度2) private thresholdVal = 3; // 下の配列の添え字に相当する値。しきい値以上のものについて通知を出す。 普段は3(震度2)
private earthquakeIntensityIndex: string[] = [ private earthquakeIntensityIndex: string[] = [
"0未満", '0未満',
"0", '0',
"1", '1',
"2", '2',
"3", '3',
"4", '4',
"5弱", '5弱',
"5強", '5強',
"6弱", '6弱',
"6強", '6強',
"7", '7',
]; ];
@autobind @autobind
@ -72,7 +72,7 @@ export default class extends Module {
@autobind @autobind
private async createListenServer() { private async createListenServer() {
http.createServer(async (req, res) => { http.createServer(async (req, res) => {
this.message = ""; this.message = '';
const buffers: Buffer[] = []; const buffers: Buffer[] = [];
for await (const chunk of req) { for await (const chunk of req) {
buffers.push(chunk); buffers.push(chunk);
@ -88,7 +88,7 @@ export default class extends Module {
}), }),
); );
if (rawDataJSON.type == "intensity_report") { if (rawDataJSON.type == 'intensity_report') {
if (rawDataJSON.max_index >= this.thresholdVal - 1) { if (rawDataJSON.max_index >= this.thresholdVal - 1) {
// 日付時刻は、yyyy-mm-dd hh:mm:ss // 日付時刻は、yyyy-mm-dd hh:mm:ss
const time = new Date(parseInt(rawDataJSON.time)); const time = new Date(parseInt(rawDataJSON.time));
@ -106,13 +106,13 @@ export default class extends Module {
}\n\n${ }\n\n${
data.intensity_list.map((intensity) => data.intensity_list.map((intensity) =>
`震度${this.earthquakeIntensityIndex[intensity.index + 1]}: ${ `震度${this.earthquakeIntensityIndex[intensity.index + 1]}: ${
intensity.region_list.join(" ") intensity.region_list.join(' ')
}` }`,
).join("\n") ).join('\n')
}\n\`\`\``; }\n\`\`\``;
} }
} }
if (rawDataJSON.type == "eew") { // これ使わなさそうだしとりあえず入らないようにした if (rawDataJSON.type == 'eew') { // これ使わなさそうだしとりあえず入らないようにした
const data: 緊急地震速報 = { const data: 緊急地震速報 = {
type: rawDataJSON.type, type: rawDataJSON.type,
time: new Date(parseInt(rawDataJSON.time)), time: new Date(parseInt(rawDataJSON.time)),
@ -126,7 +126,7 @@ export default class extends Module {
index: rawDataJSON.index, index: rawDataJSON.index,
}; };
if (data.report == "final") { // && data.index >= this.thresholdVal - 1 if (data.report == 'final') { // && data.index >= this.thresholdVal - 1
const timeString = `${data.time.getFullYear()}-${(data.time.getMonth() + const timeString = `${data.time.getFullYear()}-${(data.time.getMonth() +
1).toString().padStart(2, '0')}-${data.time.getDate().toString().padStart(2, '0')} ${data.time.getHours().toString().padStart(2, '0')}:${data.time.getMinutes().toString().padStart(2, '0')}:${data.time.getSeconds().toString().padStart(2, '0')}`; 1).toString().padStart(2, '0')}-${data.time.getDate().toString().padStart(2, '0')} ${data.time.getHours().toString().padStart(2, '0')}:${data.time.getMinutes().toString().padStart(2, '0')}:${data.time.getSeconds().toString().padStart(2, '0')}`;
this.message = `\`\`\`\n緊急地震速報(最終報)\n${timeString}\n震源地: ${data.epicenter}\n震源の深さ: ${data.depth}\n最大予測震度: ${this.earthquakeIntensityIndex[data.index + 1]}\nマグニチュード: ${data.magnitude}\n\`\`\``; this.message = `\`\`\`\n緊急地震速報(最終報)\n${timeString}\n震源地: ${data.epicenter}\n震源の深さ: ${data.depth}\n最大予測震度: ${this.earthquakeIntensityIndex[data.index + 1]}\nマグニチュード: ${data.magnitude}\n\`\`\``;
@ -138,10 +138,10 @@ export default class extends Module {
console.table(rawDataJSON.intensity_list); // デバッグ用 console.table(rawDataJSON.intensity_list); // デバッグ用
} }
this.returnResponse(res, "ok"); this.returnResponse(res, 'ok');
if (this.message) { if (this.message) {
this.ai.post({ this.ai.post({
visibility: "home", visibility: 'home',
text: this.message, text: this.message,
}); });
} }
@ -152,7 +152,7 @@ export default class extends Module {
@autobind @autobind
private returnResponse(res: http.ServerResponse, text: string) { private returnResponse(res: http.ServerResponse, text: string) {
res.writeHead(200, { res.writeHead(200, {
"Content-Type": "text/plain", 'Content-Type': 'text/plain',
}); });
res.end(text); res.end(text);
} }

View file

@ -32,7 +32,7 @@ export default class extends Module {
} }
this.ai.api('notes/reactions/create', { this.ai.api('notes/reactions/create', {
noteId: note.id, noteId: note.id,
reaction: reaction reaction: reaction,
}); });
}; };
@ -45,7 +45,7 @@ export default class extends Module {
return await react(':erait:'); return await react(':erait:');
} }
if (includes(note.text, ['いい']) && (includes(note.text, ["?"]) || includes(note.text, [""]))) { if (includes(note.text, ['いい']) && (includes(note.text, ['?']) || includes(note.text, ['']))) {
// 50%の確率で":dame:"または":yattare:"を返す // 50%の確率で":dame:"または":yattare:"を返す
if (Math.random() < 0.5) { if (Math.random() < 0.5) {
return react(':dame:'); return react(':dame:');
@ -68,14 +68,14 @@ export default class extends Module {
return react(customEmojis[0]); return react(customEmojis[0]);
} }
const emojis = parse(note.text).map(x => x.text); const emojis = parse(note.text).map((x) => x.text);
if (emojis.length > 0) { if (emojis.length > 0) {
// 絵文字が複数種類ある場合はキャンセル // 絵文字が複数種類ある場合はキャンセル
if (!emojis.every((val, i, arr) => val === arr[0])) return; if (!emojis.every((val, i, arr) => val === arr[0])) return;
this.log(`Emoji detected - ${emojis[0]}`); this.log(`Emoji detected - ${emojis[0]}`);
let reaction = emojis[0]; const reaction = emojis[0];
switch (reaction) { switch (reaction) {
case '✊': return react('🖐', true); case '✊': return react('🖐', true);
@ -93,7 +93,7 @@ export default class extends Module {
if (includes(note.text, ['ずなず']) || includes(note.text, ['ずにゃず'])) return react('🙌'); if (includes(note.text, ['ずなず']) || includes(note.text, ['ずにゃず'])) return react('🙌');
if (includes(note.text, ['なず']) || includes(note.text, ['にゃず'])) { if (includes(note.text, ['なず']) || includes(note.text, ['にゃず'])) {
if (this.ai.isMaster(note.userId)) { if (this.ai.isMaster(note.userId)) {
return react(':google_hart:') return react(':google_hart:');
} }
return react(':oltu:'); return react(':oltu:');
}; };
@ -101,8 +101,8 @@ export default class extends Module {
const gameReact = [ const gameReact = [
':ysvi:', ':ysvi:',
':ysf:', ':ysf:',
':yso:' ':yso:',
] ];
if (includes(note.text, ['おゲームするかしら'])) { if (includes(note.text, ['おゲームするかしら'])) {
// gameReactの中からランダムに選択 // gameReactの中からランダムに選択
return react(gameReact[Math.floor(Math.random() * gameReact.length)]); return react(gameReact[Math.floor(Math.random() * gameReact.length)]);

View file

@ -30,8 +30,8 @@ const hands = [
'🤙', '🤙',
'💪', '💪',
['💪', '✌'], ['💪', '✌'],
'🖕' '🖕',
] ];
const faces = [ const faces = [
'😀', '😀',
@ -123,8 +123,8 @@ const faces = [
'🤠', '🤠',
'🗿', '🗿',
'🤖', '🤖',
'👽' '👽',
] ];
export default class extends Module { export default class extends Module {
public readonly name = 'emoji'; public readonly name = 'emoji';
@ -132,7 +132,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }

View file

@ -8,7 +8,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -20,11 +20,11 @@ export default class extends Module {
userId: msg.userId, userId: msg.userId,
}); });
return { return {
reaction: msg.friend.love >= 0 ? 'like' : null reaction: msg.friend.love >= 0 ? 'like' : null,
}; };
} else { } else {
return { return {
reaction: msg.friend.love >= 0 ? 'hmm' : null reaction: msg.friend.love >= 0 ? 'hmm' : null,
}; };
} }
} else { } else {

View file

@ -43,7 +43,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -56,7 +56,7 @@ export default class extends Module {
const omikuji = blessing[Math.floor(rng() * blessing.length)]; const omikuji = blessing[Math.floor(rng() * blessing.length)];
const item = genItem(rng); const item = genItem(rng);
msg.reply(`**${omikuji}🎉**\nラッキーアイテム: ${item}`, { msg.reply(`**${omikuji}🎉**\nラッキーアイテム: ${item}`, {
cw: serifs.fortune.cw(msg.friend.name) cw: serifs.fortune.cw(msg.friend.name),
}); });
return true; return true;
} else { } else {

View file

@ -19,12 +19,12 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
this.guesses = this.ai.getCollection('guessingGame', { this.guesses = this.ai.getCollection('guessingGame', {
indices: ['userId'] indices: ['userId'],
}); });
return { return {
mentionHook: this.mentionHook, mentionHook: this.mentionHook,
contextHook: this.contextHook contextHook: this.contextHook,
}; };
} }
@ -34,7 +34,7 @@ export default class extends Module {
const exist = this.guesses.findOne({ const exist = this.guesses.findOne({
userId: msg.userId, userId: msg.userId,
isEnded: false isEnded: false,
}); });
if (!msg.isDm) { if (!msg.isDm) {
@ -55,10 +55,10 @@ export default class extends Module {
tries: [], tries: [],
isEnded: false, isEnded: false,
startedAt: Date.now(), startedAt: Date.now(),
endedAt: null endedAt: null,
}); });
msg.reply(serifs.guessingGame.started).then(reply => { msg.reply(serifs.guessingGame.started).then((reply) => {
this.subscribeReply(msg.userId, msg.isDm, msg.isDm ? msg.userId : reply.id); this.subscribeReply(msg.userId, msg.isDm, msg.isDm ? msg.userId : reply.id);
}); });
@ -71,7 +71,7 @@ export default class extends Module {
const exist = this.guesses.findOne({ const exist = this.guesses.findOne({
userId: msg.userId, userId: msg.userId,
isEnded: false isEnded: false,
}); });
// 処理の流れ上、実際にnullになることは無さそうだけど一応 // 処理の流れ上、実際にnullになることは無さそうだけど一応
@ -92,7 +92,7 @@ export default class extends Module {
const guess = msg.extractedText.match(/[0-9]+/); const guess = msg.extractedText.match(/[0-9]+/);
if (guess == null) { if (guess == null) {
msg.reply(serifs.guessingGame.nan).then(reply => { msg.reply(serifs.guessingGame.nan).then((reply) => {
this.subscribeReply(msg.userId, msg.isDm, reply.id); this.subscribeReply(msg.userId, msg.isDm, reply.id);
}); });
return; return;
@ -109,13 +109,13 @@ export default class extends Module {
let end = false; let end = false;
if (exist.secret < g) { if (exist.secret < g) {
text = firsttime text = firsttime ?
? serifs.guessingGame.less(g.toString()) serifs.guessingGame.less(g.toString()) :
: serifs.guessingGame.lessAgain(g.toString()); serifs.guessingGame.lessAgain(g.toString());
} else if (exist.secret > g) { } else if (exist.secret > g) {
text = firsttime text = firsttime ?
? serifs.guessingGame.grater(g.toString()) serifs.guessingGame.grater(g.toString()) :
: serifs.guessingGame.graterAgain(g.toString()); serifs.guessingGame.graterAgain(g.toString());
} else { } else {
end = true; end = true;
text = serifs.guessingGame.congrats(exist.tries.length.toString()); text = serifs.guessingGame.congrats(exist.tries.length.toString());
@ -129,7 +129,7 @@ export default class extends Module {
this.guesses.update(exist); this.guesses.update(exist);
msg.reply(text).then(reply => { msg.reply(text).then((reply) => {
if (!end) { if (!end) {
this.subscribeReply(msg.userId, msg.isDm, reply.id); this.subscribeReply(msg.userId, msg.isDm, reply.id);
} }

View file

@ -36,7 +36,7 @@ export default class extends Module {
return { return {
mentionHook: this.mentionHook, mentionHook: this.mentionHook,
contextHook: this.contextHook contextHook: this.contextHook,
}; };
} }
@ -52,7 +52,7 @@ export default class extends Module {
// 現在アクティブなゲームがある場合 // 現在アクティブなゲームがある場合
if (!recentGame.isEnded) { if (!recentGame.isEnded) {
msg.reply(serifs.kazutori.alreadyStarted, { msg.reply(serifs.kazutori.alreadyStarted, {
renote: recentGame.postId renote: recentGame.postId,
}); });
return true; return true;
} }
@ -65,14 +65,14 @@ export default class extends Module {
} }
const post = await this.ai.post({ const post = await this.ai.post({
text: serifs.kazutori.intro(limitMinutes) text: serifs.kazutori.intro(limitMinutes),
}); });
this.games.insertOne({ this.games.insertOne({
votes: [], votes: [],
isEnded: false, isEnded: false,
startedAt: Date.now(), startedAt: Date.now(),
postId: post.id postId: post.id,
}); });
this.subscribeReply(null, false, post.id); this.subscribeReply(null, false, post.id);
@ -84,38 +84,48 @@ export default class extends Module {
@autobind @autobind
private async contextHook(key: any, msg: Message) { private async contextHook(key: any, msg: Message) {
if (msg.text == null) return { if (msg.text == null) {
reaction: 'hmm' return {
reaction: 'hmm',
}; };
}
const game = this.games.findOne({ const game = this.games.findOne({
isEnded: false isEnded: false,
}); });
// 処理の流れ上、実際にnullになることは無さそうだけど一応 // 処理の流れ上、実際にnullになることは無さそうだけど一応
if (game == null) return; if (game == null) return;
// 既に数字を取っていたら // 既に数字を取っていたら
if (game.votes.some(x => x.user.id == msg.userId)) return { if (game.votes.some((x) => x.user.id == msg.userId)) {
reaction: 'confused' return {
reaction: 'confused',
}; };
}
const match = msg.extractedText.match(/[0-9]+/); const match = msg.extractedText.match(/[0-9]+/);
if (match == null) return { if (match == null) {
reaction: 'hmm' return {
reaction: 'hmm',
}; };
}
const num = parseInt(match[0], 10); const num = parseInt(match[0], 10);
// 整数じゃない // 整数じゃない
if (!Number.isInteger(num)) return { if (!Number.isInteger(num)) {
reaction: 'hmm' return {
reaction: 'hmm',
}; };
}
// 範囲外 // 範囲外
if (num < 0 || num > 100) return { if (num < 0 || num > 100) {
reaction: 'confused' return {
reaction: 'confused',
}; };
}
this.log(`Voted ${num} by ${msg.user.id}`); this.log(`Voted ${num} by ${msg.user.id}`);
@ -124,15 +134,15 @@ export default class extends Module {
user: { user: {
id: msg.user.id, id: msg.user.id,
username: msg.user.username, username: msg.user.username,
host: msg.user.host host: msg.user.host,
}, },
number: num number: num,
}); });
this.games.update(game); this.games.update(game);
return { return {
reaction: 'like' reaction: 'like',
}; };
} }
@ -142,7 +152,7 @@ export default class extends Module {
@autobind @autobind
private crawleGameEnd() { private crawleGameEnd() {
const game = this.games.findOne({ const game = this.games.findOne({
isEnded: false isEnded: false,
}); });
if (game == null) return; if (game == null) return;
@ -167,19 +177,19 @@ export default class extends Module {
if (game.votes.length <= 1) { if (game.votes.length <= 1) {
this.ai.post({ this.ai.post({
text: serifs.kazutori.onagare, text: serifs.kazutori.onagare,
renoteId: game.postId renoteId: game.postId,
}); });
return; return;
} }
let results: string[] = []; const results: string[] = [];
let winner: Game['votes'][0]['user'] | null = null; let winner: Game['votes'][0]['user'] | null = null;
for (let i = 100; i >= 0; i--) { for (let i = 100; i >= 0; i--) {
const users = game.votes const users = game.votes
.filter(x => x.number == i) .filter((x) => x.number == i)
.map(x => x.user); .map((x) => x.user);
if (users.length == 1) { if (users.length == 1) {
if (winner == null) { if (winner == null) {
@ -190,21 +200,21 @@ export default class extends Module {
results.push(` ${i}: ${acct(users[0])}`); results.push(` ${i}: ${acct(users[0])}`);
} }
} else if (users.length > 1) { } else if (users.length > 1) {
results.push(`${i}: ${users.map(u => acct(u)).join(' ')}`); results.push(`${i}: ${users.map((u) => acct(u)).join(' ')}`);
} }
} }
const winnerFriend = winner ? this.ai.lookupFriend(winner.id) : null; const winnerFriend = winner ? this.ai.lookupFriend(winner.id) : null;
const name = winnerFriend ? winnerFriend.name : null; const name = winnerFriend ? winnerFriend.name : null;
const text = results.join('\n') + '\n\n' + (winner const text = results.join('\n') + '\n\n' + (winner ?
? serifs.kazutori.finishWithWinner(acct(winner), name) serifs.kazutori.finishWithWinner(acct(winner), name) :
: serifs.kazutori.finishWithNoWinner); serifs.kazutori.finishWithNoWinner);
this.ai.post({ this.ai.post({
text: text, text: text,
cw: serifs.kazutori.finish, cw: serifs.kazutori.finish,
renoteId: game.postId renoteId: game.postId,
}); });
this.unsubscribeReply(null); this.unsubscribeReply(null);

View file

@ -7,7 +7,7 @@ import { mecab } from './mecab';
import {Note} from '@/misskey/note'; import {Note} from '@/misskey/note';
function kanaToHira(str: string) { function kanaToHira(str: string) {
return str.replace(/[\u30a1-\u30f6]/g, match => { return str.replace(/[\u30a1-\u30f6]/g, (match) => {
const chr = match.charCodeAt(0) - 0x60; const chr = match.charCodeAt(0) - 0x60;
return String.fromCharCode(chr); return String.fromCharCode(chr);
}); });
@ -26,7 +26,7 @@ export default class extends Module {
if (!config.keywordEnabled) return {}; if (!config.keywordEnabled) return {};
this.learnedKeywords = this.ai.getCollection('_keyword_learnedKeywords', { this.learnedKeywords = this.ai.getCollection('_keyword_learnedKeywords', {
indices: ['userId'] indices: ['userId'],
}); });
setInterval(this.learn, 1000 * 60 * 60); setInterval(this.learn, 1000 * 60 * 60);
@ -37,7 +37,7 @@ export default class extends Module {
@autobind @autobind
private async learn() { private async learn() {
const tl = await this.ai.api('notes/local-timeline', { const tl = await this.ai.api('notes/local-timeline', {
limit: 30 limit: 30,
}); });
const interestedNotes = tl.filter((note: Note) => const interestedNotes = tl.filter((note: Note) =>
@ -49,7 +49,7 @@ export default class extends Module {
for (const note of interestedNotes) { for (const note of interestedNotes) {
const tokens = await mecab(note.text, config.mecab, config.mecabDic); const tokens = await mecab(note.text, config.mecab, config.mecabDic);
const keywordsInThisNote = tokens.filter(token => token[2] == '固有名詞' && token[8] != null); const keywordsInThisNote = tokens.filter((token) => token[2] == '固有名詞' && token[8] != null);
keywords = keywords.concat(keywordsInThisNote); keywords = keywords.concat(keywordsInThisNote);
} }
@ -59,7 +59,7 @@ export default class extends Module {
const keyword = keywords.sort((a, b) => a[0].length < b[0].length ? 1 : -1)[rnd]; const keyword = keywords.sort((a, b) => a[0].length < b[0].length ? 1 : -1)[rnd];
const exist = this.learnedKeywords.findOne({ const exist = this.learnedKeywords.findOne({
keyword: keyword[0] keyword: keyword[0],
}); });
let text: string; let text: string;
@ -69,14 +69,14 @@ export default class extends Module {
} else { } else {
this.learnedKeywords.insertOne({ this.learnedKeywords.insertOne({
keyword: keyword[0], keyword: keyword[0],
learnedAt: Date.now() learnedAt: Date.now(),
}); });
text = serifs.keyword.learned(keyword[0], kanaToHira(keyword[8])); text = serifs.keyword.learned(keyword[0], kanaToHira(keyword[8]));
} }
this.ai.post({ this.ai.post({
text: text text: text,
}); });
} }
} }

View file

@ -1,6 +1,6 @@
import * as gen from 'random-seed'; import * as gen from 'random-seed';
import {CellType} from './maze'; import {CellType} from './maze';
import {mazeSize} from './index' import {mazeSize} from './index';
const cellVariants = { const cellVariants = {
void: { void: {
@ -92,7 +92,7 @@ export function genMaze(seed: string, complexity: mazeSize): CellType[][] {
return 11 + rand(21); return 11 + rand(21);
} }
let mazeSize: number = decisionSize(complexity); const mazeSize: number = decisionSize(complexity);
const donut = rand(3) === 0; const donut = rand(3) === 0;

View file

@ -16,7 +16,7 @@ export default class extends Module {
setInterval(this.post, 1000 * 60 * 3); setInterval(this.post, 1000 * 60 * 3);
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -36,7 +36,7 @@ export default class extends Module {
this.log('Posting...'); this.log('Posting...');
this.ai.post({ this.ai.post({
text: serifs.maze.post, text: serifs.maze.post,
fileIds: [file.id] fileIds: [file.id],
}); });
} }
@ -51,7 +51,7 @@ export default class extends Module {
this.log('Image uploading...'); this.log('Image uploading...');
const file = await this.ai.upload(data, { const file = await this.ai.upload(data, {
filename: 'maze.png', filename: 'maze.png',
contentType: 'image/png' contentType: 'image/png',
}); });
return file; return file;
@ -73,7 +73,7 @@ export default class extends Module {
msg.reply(serifs.maze.foryou, {file}); msg.reply(serifs.maze.foryou, {file});
}, 3000); }, 3000);
return { return {
reaction: 'like' reaction: 'like',
}; };
} else { } else {
return false; return false;

View file

@ -9,7 +9,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -17,8 +17,8 @@ export default class extends Module {
private async mentionHook(msg: Message): Promise<boolean> { private async mentionHook(msg: Message): Promise<boolean> {
if (msg.text && msg.text.includes('ごはん')) { if (msg.text && msg.text.includes('ごはん')) {
// 1~2535111の適当な数字を取得 // 1~2535111の適当な数字を取得
const random_number = Math.floor(Math.random() * 2535111) + 1; const randomNumber = Math.floor(Math.random() * 2535111) + 1;
const url = `https://cookpad.com/recipe/${random_number}`; const url = `https://cookpad.com/recipe/${randomNumber}`;
// testUrlして、200以外なら再取得 // testUrlして、200以外なら再取得
const res = await fetch(url); const res = await fetch(url);
if (res.status !== 200) { if (res.status !== 200) {
@ -31,7 +31,7 @@ export default class extends Module {
// titleから改行を除去 // titleから改行を除去
title = title!.replace(/\n/g, ''); title = title!.replace(/\n/g, '');
msg.reply(`こんなのどう?> [${title}](${url})`, { msg.reply(`こんなのどう?> [${title}](${url})`, {
immediate: true immediate: true,
}); });
return true; return true;
} }

View file

@ -43,7 +43,7 @@ export default class extends Module {
// TODO: 季節に応じたセリフ // TODO: 季節に応じたセリフ
this.ai.post({ this.ai.post({
text: typeof note === 'function' ? note() : note text: typeof note === 'function' ? note() : note,
}); });
} }
} }

View file

@ -8,7 +8,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -18,14 +18,14 @@ export default class extends Module {
if (msg.text.includes('おい')) { if (msg.text.includes('おい')) {
if (this.ai.isMaster(msg.userId)) { if (this.ai.isMaster(msg.userId)) {
msg.reply('はい。。。', { msg.reply('はい。。。', {
immediate: true immediate: true,
}); });
} else { } else {
return false; return false;
} }
} else { } else {
msg.reply('PONG!', { msg.reply('PONG!', {
immediate: true immediate: true,
}); });
} }
return true; return true;

View file

@ -79,7 +79,7 @@ export default class extends Module {
choices, choices,
expiredAfter: duration, expiredAfter: duration,
multiple: false, multiple: false,
} },
}); });
// タイマーセット // タイマーセット
@ -121,7 +121,7 @@ export default class extends Module {
} }
} }
const mostVotedChoices = choices.filter(choice => choice.votes === mostVotedChoice.votes); const mostVotedChoices = choices.filter((choice) => choice.votes === mostVotedChoice.votes);
if (mostVotedChoice.votes === 0) { if (mostVotedChoice.votes === 0) {
this.ai.post({ // TODO: Extract serif this.ai.post({ // TODO: Extract serif
@ -135,7 +135,7 @@ export default class extends Module {
renoteId: noteId, renoteId: noteId,
}); });
} else { } else {
const choices = mostVotedChoices.map(choice => `${choice.text}`).join('と'); const choices = mostVotedChoices.map((choice) => `${choice.text}`).join('と');
this.ai.post({ // TODO: Extract serif this.ai.post({ // TODO: Extract serif
cw: `${title}アンケートの結果発表です!`, cw: `${title}アンケートの結果発表です!`,
text: `結果は${mostVotedChoice.votes}票の${choices}でした!`, text: `結果は${mostVotedChoice.votes}票の${choices}でした!`,

View file

@ -24,7 +24,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
this.reminds = this.ai.getCollection('reminds', { this.reminds = this.ai.getCollection('reminds', {
indices: ['userId', 'id'] indices: ['userId', 'id'],
}); });
return { return {
@ -44,9 +44,9 @@ export default class extends Module {
userId: msg.userId, userId: msg.userId,
}); });
const getQuoteLink = id => `[${id}](${config.host}/notes/${id})`; const getQuoteLink = (id) => `[${id}](${config.host}/notes/${id})`;
msg.reply(serifs.reminder.reminds + '\n' + reminds.map(remind => `${remind.thing ? remind.thing : getQuoteLink(remind.quoteId)}`).join('\n')); msg.reply(serifs.reminder.reminds + '\n' + reminds.map((remind) => `${remind.thing ? remind.thing : getQuoteLink(remind.quoteId)}`).join('\n'));
return true; return true;
} }
@ -87,13 +87,13 @@ export default class extends Module {
// メンションをsubscribe // メンションをsubscribe
this.subscribeReply(remind!.id, msg.isDm, msg.isDm ? msg.userId : msg.id, { this.subscribeReply(remind!.id, msg.isDm, msg.isDm ? msg.userId : msg.id, {
id: remind!.id id: remind!.id,
}); });
if (msg.quoteId) { if (msg.quoteId) {
// 引用元をsubscribe // 引用元をsubscribe
this.subscribeReply(remind!.id, false, msg.quoteId, { this.subscribeReply(remind!.id, false, msg.quoteId, {
id: remind!.id id: remind!.id,
}); });
} }
@ -142,7 +142,7 @@ export default class extends Module {
@autobind @autobind
private async timeoutCallback(data) { private async timeoutCallback(data) {
const remind = this.reminds.findOne({ const remind = this.reminds.findOne({
id: data.id id: data.id,
}); });
if (remind == null) return; if (remind == null) return;
@ -155,13 +155,13 @@ export default class extends Module {
let reply; let reply;
if (remind.isDm) { if (remind.isDm) {
this.ai.sendMessage(friend.userId, { this.ai.sendMessage(friend.userId, {
text: serifs.reminder.notifyWithThing(remind.thing, friend.name) text: serifs.reminder.notifyWithThing(remind.thing, friend.name),
}); });
} else { } else {
try { try {
reply = await this.ai.post({ reply = await this.ai.post({
renoteId: remind.thing == null && remind.quoteId ? remind.quoteId : remind.id, renoteId: remind.thing == null && remind.quoteId ? remind.quoteId : remind.id,
text: acct(friend.doc.user) + ' ' + serifs.reminder.notify(friend.name) text: acct(friend.doc.user) + ' ' + serifs.reminder.notify(friend.name),
}); });
} catch (err) { } catch (err) {
// renote対象が消されていたらリマインダー解除 // renote対象が消されていたらリマインダー解除
@ -175,7 +175,7 @@ export default class extends Module {
} }
this.subscribeReply(remind.id, remind.isDm, remind.isDm ? remind.userId : reply.id, { this.subscribeReply(remind.id, remind.isDm, remind.isDm ? remind.userId : reply.id, {
id: remind.id id: remind.id,
}); });
// タイマーセット // タイマーセット

View file

@ -22,7 +22,7 @@ const titles = [
'さん', 'サン', 'サン', '㌠', 'さん', 'サン', 'サン', '㌠',
'ちゃん', 'チャン', 'チャン', 'ちゃん', 'チャン', 'チャン',
'君', 'くん', 'クン', 'クン', '君', 'くん', 'クン', 'クン',
'先生', 'せんせい', 'センセイ', 'センセイ' '先生', 'せんせい', 'センセイ', 'センセイ',
]; ];
class Session { class Session {
@ -63,11 +63,11 @@ class Session {
private get userName(): string { private get userName(): string {
const name = getUserName(this.user); const name = getUserName(this.user);
return `?[${name}](${config.host}/@${this.user.username})${titles.some(x => name.endsWith(x)) ? '' : 'さん'}`; return `?[${name}](${config.host}/@${this.user.username})${titles.some((x) => name.endsWith(x)) ? '' : 'さん'}`;
} }
private get strength(): number { private get strength(): number {
return this.form.find(i => i.id == 'strength').value; return this.form.find((i) => i.id == 'strength').value;
} }
private get isSettai(): boolean { private get isSettai(): boolean {
@ -75,7 +75,7 @@ class Session {
} }
private get allowPost(): boolean { private get allowPost(): boolean {
return this.form.find(i => i.id == 'publish').value; return this.form.find((i) => i.id == 'publish').value;
} }
private get url(): string { private get url(): string {
@ -94,21 +94,21 @@ class Session {
case 'ended': this.onEnded(msg.body); break; case 'ended': this.onEnded(msg.body); break;
case 'set': this.onSet(msg.body); break; case 'set': this.onSet(msg.body); break;
} }
} };
// 親プロセスからデータをもらう // 親プロセスからデータをもらう
private onInit = (msg: any) => { private onInit = (msg: any) => {
this.game = msg.game; this.game = msg.game;
this.form = msg.form; this.form = msg.form;
this.account = msg.account; this.account = msg.account;
} };
/** /**
* *
*/ */
private onUpdateForn = (msg: any) => { private onUpdateForn = (msg: any) => {
this.form.find(i => i.id == msg.id).value = msg.value; this.form.find((i) => i.id == msg.id).value = msg.value;
} };
/** /**
* *
@ -117,7 +117,7 @@ class Session {
this.game = msg; this.game = msg;
// TLに投稿する // TLに投稿する
this.postGameStarted().then(note => { this.postGameStarted().then((note) => {
this.startedNote = note; this.startedNote = note;
}); });
@ -125,10 +125,10 @@ class Session {
this.o = new Reversi(this.game.map, { this.o = new Reversi(this.game.map, {
isLlotheo: this.game.isLlotheo, isLlotheo: this.game.isLlotheo,
canPutEverywhere: this.game.canPutEverywhere, canPutEverywhere: this.game.canPutEverywhere,
loopedBoard: this.game.loopedBoard loopedBoard: this.game.loopedBoard,
}); });
this.maxTurn = this.o.map.filter(p => p === 'empty').length - this.o.board.filter(x => x != null).length; this.maxTurn = this.o.map.filter((p) => p === 'empty').length - this.o.board.filter((x) => x != null).length;
// #region 隅の位置計算など // #region 隅の位置計算など
@ -162,7 +162,7 @@ class Session {
// -+- // -+-
// //
(get(x - 1, y) == 'empty' && get(x + 1, y) == 'empty') (get(x - 1, y) == 'empty' && get(x + 1, y) == 'empty')
) );
const isSumi = !isNotSumi; const isSumi = !isNotSumi;
@ -191,7 +191,7 @@ class Session {
check(x, y + 1) || // 下 check(x, y + 1) || // 下
check(x - 1, y + 1) || // 左下 check(x - 1, y + 1) || // 左下
check(x - 1, y ) // 左 check(x - 1, y ) // 左
) );
if (isSumiNear) this.sumiNearIndexes.push(i); if (isSumiNear) this.sumiNearIndexes.push(i);
}); });
@ -204,7 +204,7 @@ class Session {
if (this.botColor) { if (this.botColor) {
this.think(); this.think();
} }
} };
/** /**
* *
@ -212,7 +212,7 @@ class Session {
private onEnded = async (msg: any) => { private onEnded = async (msg: any) => {
// ストリームから切断 // ストリームから切断
process.send!({ process.send!({
type: 'ended' type: 'ended',
}); });
let text: string; let text: string;
@ -248,7 +248,7 @@ class Session {
await this.post(text, this.startedNote); await this.post(text, this.startedNote);
process.exit(); process.exit();
} };
/** /**
* *
@ -260,7 +260,7 @@ class Session {
if (msg.next === this.botColor) { if (msg.next === this.botColor) {
this.think(); this.think();
} }
} };
/** /**
* Botにとってある局面がどれだけ有利か静的に評価する * Botにとってある局面がどれだけ有利か静的に評価する
@ -299,7 +299,7 @@ class Session {
if (this.isSettai) score = -score; if (this.isSettai) score = -score;
return score; return score;
} };
private think = () => { private think = () => {
console.log(`(${this.currentTurn}/${this.maxTurn}) Thinking...`); console.log(`(${this.currentTurn}/${this.maxTurn}) Thinking...`);
@ -344,9 +344,9 @@ class Session {
this.o.undo(); this.o.undo();
// 接待なら自分が負けた方が高スコア // 接待なら自分が負けた方が高スコア
return this.isSettai return this.isSettai ?
? winner !== this.botColor ? score : -score winner !== this.botColor ? score : -score :
: winner === this.botColor ? score : -score; winner === this.botColor ? score : -score;
} }
if (depth === maxDepth) { if (depth === maxDepth) {
@ -391,7 +391,7 @@ class Session {
}; };
const cans = this.o.canPutSomewhere(this.botColor); const cans = this.o.canPutSomewhere(this.botColor);
const scores = cans.map(p => dive(p)); const scores = cans.map((p) => dive(p));
const pos = cans[scores.indexOf(Math.max(...scores))]; const pos = cans[scores.indexOf(Math.max(...scores))];
console.log('Thinked:', pos); console.log('Thinked:', pos);
@ -400,21 +400,21 @@ class Session {
setTimeout(() => { setTimeout(() => {
process.send!({ process.send!({
type: 'put', type: 'put',
pos pos,
}); });
}, 500); }, 500);
} };
/** /**
* Misskeyに投稿します * Misskeyに投稿します
*/ */
private postGameStarted = async () => { private postGameStarted = async () => {
const text = this.isSettai const text = this.isSettai ?
? serifs.reversi.startedSettai(this.userName) serifs.reversi.startedSettai(this.userName) :
: serifs.reversi.started(this.userName, this.strength.toString()); serifs.reversi.started(this.userName, this.strength.toString());
return await this.post(`${text}\n→[観戦する](${this.url})`); return await this.post(`${text}\n→[観戦する](${this.url})`);
} };
/** /**
* Misskeyに投稿します * Misskeyに投稿します
@ -425,7 +425,7 @@ class Session {
const body = { const body = {
i: config.i, i: config.i,
text: text, text: text,
visibility: 'home' visibility: 'home',
} as any; } as any;
if (renote) { if (renote) {
@ -434,7 +434,7 @@ class Session {
try { try {
const res = await request.post(`${config.host}/api/notes/create`, { const res = await request.post(`${config.host}/api/notes/create`, {
json: body json: body,
}); });
return res.createdNote; return res.createdNote;
@ -445,7 +445,7 @@ class Session {
} else { } else {
return null; return null;
} }
} };
} }
new Session(); new Session();

View file

@ -22,24 +22,24 @@ export default class extends Module {
this.reversiConnection = this.ai.connection.useSharedConnection('gamesReversi'); this.reversiConnection = this.ai.connection.useSharedConnection('gamesReversi');
// 招待されたとき // 招待されたとき
this.reversiConnection.on('invited', msg => this.onReversiInviteMe(msg.parent)); this.reversiConnection.on('invited', (msg) => this.onReversiInviteMe(msg.parent));
// マッチしたとき // マッチしたとき
this.reversiConnection.on('matched', msg => this.onReversiGameStart(msg)); this.reversiConnection.on('matched', (msg) => this.onReversiGameStart(msg));
if (config.reversiEnabled) { if (config.reversiEnabled) {
const mainStream = this.ai.connection.useSharedConnection('main'); const mainStream = this.ai.connection.useSharedConnection('main');
mainStream.on('pageEvent', msg => { mainStream.on('pageEvent', (msg) => {
if (msg.event === 'inviteReversi') { if (msg.event === 'inviteReversi') {
this.ai.api('games/reversi/match', { this.ai.api('games/reversi/match', {
userId: msg.user.id userId: msg.user.id,
}); });
} }
}); });
} }
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -50,7 +50,7 @@ export default class extends Module {
msg.reply(serifs.reversi.ok); msg.reply(serifs.reversi.ok);
this.ai.api('games/reversi/match', { this.ai.api('games/reversi/match', {
userId: msg.userId userId: msg.userId,
}); });
} else { } else {
msg.reply(serifs.reversi.decline); msg.reply(serifs.reversi.decline);
@ -69,7 +69,7 @@ export default class extends Module {
if (config.reversiEnabled) { if (config.reversiEnabled) {
// 承認 // 承認
const game = await this.ai.api('games/reversi/match', { const game = await this.ai.api('games/reversi/match', {
userId: inviter.id userId: inviter.id,
}); });
this.onReversiGameStart(game); this.onReversiGameStart(game);
@ -84,7 +84,7 @@ export default class extends Module {
// ゲームストリームに接続 // ゲームストリームに接続
const gw = this.ai.connection.connectToChannel('gamesReversiGame', { const gw = this.ai.connection.connectToChannel('gamesReversiGame', {
gameId: game.id gameId: game.id,
}); });
// フォーム // フォーム
@ -92,7 +92,7 @@ export default class extends Module {
id: 'publish', id: 'publish',
type: 'switch', type: 'switch',
label: '藍が対局情報を投稿するのを許可', label: '藍が対局情報を投稿するのを許可',
value: true value: true,
}, { }, {
id: 'strength', id: 'strength',
type: 'radio', type: 'radio',
@ -100,20 +100,20 @@ export default class extends Module {
value: 3, value: 3,
items: [{ items: [{
label: '接待', label: '接待',
value: 0 value: 0,
}, { }, {
label: '弱', label: '弱',
value: 2 value: 2,
}, { }, {
label: '中', label: '中',
value: 3 value: 3,
}, { }, {
label: '強', label: '強',
value: 4 value: 4,
}, { }, {
label: '最強', label: '最強',
value: 5 value: 5,
}] }],
}]; }];
// #region バックエンドプロセス開始 // #region バックエンドプロセス開始
@ -125,14 +125,14 @@ export default class extends Module {
body: { body: {
game: game, game: game,
form: form, form: form,
account: this.ai.account account: this.ai.account,
} },
}); });
ai.on('message', (msg: Record<string, any>) => { ai.on('message', (msg: Record<string, any>) => {
if (msg.type == 'put') { if (msg.type == 'put') {
gw.send('set', { gw.send('set', {
pos: msg.pos pos: msg.pos,
}); });
} else if (msg.type == 'ended') { } else if (msg.type == 'ended') {
gw.dispose(); gw.dispose();
@ -142,7 +142,7 @@ export default class extends Module {
}); });
// ゲームストリームから情報が流れてきたらそのままバックエンドプロセスに伝える // ゲームストリームから情報が流れてきたらそのままバックエンドプロセスに伝える
gw.addListener('*', message => { gw.addListener('*', (message) => {
ai.send(message); ai.send(message);
}); });
// #endregion // #endregion

View file

@ -39,7 +39,7 @@ export default class extends Module {
private check() { private check() {
const average = (arr) => arr.reduce((a, b) => a + b) / arr.length; const average = (arr) => arr.reduce((a, b) => a + b) / arr.length;
const cpuPercentages = this.statsLogs.map(s => s && (s.cpu_usage || s.cpu) * 100 || 0); const cpuPercentages = this.statsLogs.map((s) => s && (s.cpu_usage || s.cpu) * 100 || 0);
const cpuPercentage = average(cpuPercentages); const cpuPercentage = average(cpuPercentages);
if (cpuPercentage >= 70) { if (cpuPercentage >= 70) {
this.warn(); this.warn();
@ -71,9 +71,9 @@ export default class extends Module {
// #endregion // #endregion
this.ai.post({ this.ai.post({
visibility: "home", visibility: 'home',
localOnly: true, localOnly: true,
text: serifs.server.cpu text: serifs.server.cpu,
}); });
this.warned = true; this.warned = true;

View file

@ -24,11 +24,11 @@ export default class extends Module {
if (sleepHours >= 1) { if (sleepHours >= 1) {
this.ai.post({ this.ai.post({
text: serifs.sleepReport.report(Math.round(sleepHours)) text: serifs.sleepReport.report(Math.round(sleepHours)),
}); });
} else { } else {
this.ai.post({ this.ai.post({
text: serifs.sleepReport.reportUtatane text: serifs.sleepReport.reportUtatane,
}); });
} }
} }

View file

@ -10,16 +10,16 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@autobind @autobind
private async mentionHook(msg: Message) { private async mentionHook(msg: Message) {
// cat/Cat/ねこ/ネコ/にゃん // cat/Cat/ねこ/ネコ/にゃん
console.log(msg.text) console.log(msg.text);
if (msg.text && (msg.text.match(/(cat|Cat|ねこ|ネコ|にゃ[〜|ー]*ん)/g))) { if (msg.text && (msg.text.match(/(cat|Cat|ねこ|ネコ|にゃ[〜|ー]*ん)/g))) {
const message = "にゃ~ん!"; const message = 'にゃ~ん!';
const file = await this.getCatImage(); const file = await this.getCatImage();
this.log(file); this.log(file);
@ -27,7 +27,7 @@ export default class extends Module {
msg.reply(message, {file}); msg.reply(message, {file});
return { return {
reaction: ':blobcatmeltnomblobcatmelt:' reaction: ':blobcatmeltnomblobcatmelt:',
}; };
} else { } else {
return false; return false;

View file

@ -87,9 +87,9 @@ export default class extends Module {
if (msg.includes(['行ってくる', '行ってきます', 'いってくる', 'いってきます'])) { if (msg.includes(['行ってくる', '行ってきます', 'いってくる', 'いってきます'])) {
msg.reply( msg.reply(
msg.friend.love >= 7 msg.friend.love >= 7 ?
? serifs.core.itterassyai.love(msg.friend.name) serifs.core.itterassyai.love(msg.friend.name) :
: serifs.core.itterassyai.normal(msg.friend.name)); serifs.core.itterassyai.normal(msg.friend.name));
incLove(); incLove();
return true; return true;
} }
@ -171,7 +171,7 @@ export default class extends Module {
msg.friend.love <= -10 ? serifs.core.nadenade.hate3 : msg.friend.love <= -10 ? serifs.core.nadenade.hate3 :
msg.friend.love <= -5 ? serifs.core.nadenade.hate2 : msg.friend.love <= -5 ? serifs.core.nadenade.hate2 :
msg.friend.love <= -1 ? serifs.core.nadenade.hate1 : msg.friend.love <= -1 ? serifs.core.nadenade.hate1 :
serifs.core.nadenade.normal serifs.core.nadenade.normal,
)); ));
return true; return true;
@ -305,7 +305,7 @@ export default class extends Module {
msg.friend.decLove(); msg.friend.decLove();
return { return {
reaction: 'angry' reaction: 'angry',
}; };
} }
@ -316,7 +316,7 @@ export default class extends Module {
msg.friend.decLove(); msg.friend.decLove();
return { return {
reaction: 'angry' reaction: 'angry',
}; };
} }
@ -327,7 +327,7 @@ export default class extends Module {
msg.reply(serifs.core.shutdown); msg.reply(serifs.core.shutdown);
return { return {
reaction: 'confused' reaction: 'confused',
}; };
} }
} }

View file

@ -50,7 +50,7 @@ export default class extends Module {
isDm: msg.isDm, isDm: msg.isDm,
msgId: msg.id, msgId: msg.id,
userId: msg.friend.userId, userId: msg.friend.userId,
time: str time: str,
}); });
return true; return true;
@ -63,12 +63,12 @@ export default class extends Module {
const text = serifs.timer.notify(data.time, friend.name); const text = serifs.timer.notify(data.time, friend.name);
if (data.isDm) { if (data.isDm) {
this.ai.sendMessage(friend.userId, { this.ai.sendMessage(friend.userId, {
text: text text: text,
}); });
} else { } else {
this.ai.post({ this.ai.post({
replyId: data.msgId, replyId: data.msgId,
text: text text: text,
}); });
} }
} }

View file

@ -28,7 +28,7 @@ export default class extends Module {
const friends = this.ai.friends.find({} as any); const friends = this.ai.friends.find({} as any);
friends.forEach(f => { friends.forEach((f) => {
const friend = new Friend(this.ai, {doc: f}); const friend = new Friend(this.ai, {doc: f});
// 親愛度が5以上必要 // 親愛度が5以上必要
@ -44,7 +44,7 @@ export default class extends Module {
const text = serifs.valentine.chocolateForYou(friend.name); const text = serifs.valentine.chocolateForYou(friend.name);
this.ai.sendMessage(friend.userId, { this.ai.sendMessage(friend.userId, {
text: text text: text,
}); });
}); });
} }

View file

@ -18,14 +18,14 @@ export default class extends Module {
if (note.isFirstNote) { if (note.isFirstNote) {
setTimeout(() => { setTimeout(() => {
this.ai.api('notes/create', { this.ai.api('notes/create', {
renoteId: note.id renoteId: note.id,
}); });
}, 3000); }, 3000);
setTimeout(() => { setTimeout(() => {
this.ai.api('notes/reactions/create', { this.ai.api('notes/reactions/create', {
noteId: note.id, noteId: note.id,
reaction: 'congrats' reaction: 'congrats',
}); });
}, 5000); }, 5000);
} }

View file

@ -2,15 +2,15 @@
export default { export default {
core: { core: {
setNameOk: name => `わかりました。これからは${name}とお呼びしますね!`, setNameOk: (name) => `わかりました。これからは${name}とお呼びしますね!`,
san: 'さん付けした方がいいですか?', san: 'さん付けした方がいいですか?',
yesOrNo: '「はい」か「いいえ」しかわからないんです...', yesOrNo: '「はい」か「いいえ」しかわからないんです...',
hello: name => name ? `こんにちは、${name}` : `こんにちは♪`, hello: (name) => name ? `こんにちは、${name}` : `こんにちは♪`,
helloNight: name => name ? `こんばんは、${name}` : `こんばんは♪`, helloNight: (name) => name ? `こんばんは、${name}` : `こんばんは♪`,
goodMorning: (tension, name) => name ? `おはようございます、${name}${tension}` : `おはようございます!${tension}`, goodMorning: (tension, name) => name ? `おはようございます、${name}${tension}` : `おはようございます!${tension}`,
@ -22,54 +22,54 @@ export default {
}, },
*/ */
goodNight: name => name ? `おやすみなさい、${name}` : 'おやすみなさい!', goodNight: (name) => name ? `おやすみなさい、${name}` : 'おやすみなさい!',
omedeto: name => name ? `ありがとうございます、${name}` : 'ありがとうございます♪', omedeto: (name) => name ? `ありがとうございます、${name}` : 'ありがとうございます♪',
erait: { erait: {
general: name => name ? [ general: (name) => name ? [
`${name}、今日もえらいです!`, `${name}、今日もえらいです!`,
`${name}、今日もえらいですよ~♪` `${name}、今日もえらいですよ~♪`,
] : [ ] : [
`今日もえらいです!`, `今日もえらいです!`,
`今日もえらいですよ~♪` `今日もえらいですよ~♪`,
], ],
specify: (thing, name) => name ? [ specify: (thing, name) => name ? [
`${name}${thing}てえらいです!`, `${name}${thing}てえらいです!`,
`${name}${thing}てえらいですよ~♪` `${name}${thing}てえらいですよ~♪`,
] : [ ] : [
`${thing}てえらいです!`, `${thing}てえらいです!`,
`${thing}てえらいですよ~♪` `${thing}てえらいですよ~♪`,
], ],
specify2: (thing, name) => name ? [ specify2: (thing, name) => name ? [
`${name}${thing}でえらいです!`, `${name}${thing}でえらいです!`,
`${name}${thing}でえらいですよ~♪` `${name}${thing}でえらいですよ~♪`,
] : [ ] : [
`${thing}でえらいです!`, `${thing}でえらいです!`,
`${thing}でえらいですよ~♪` `${thing}でえらいですよ~♪`,
], ],
}, },
okaeri: { okaeri: {
love: name => name ? [ love: (name) => name ? [
`おかえりなさい、${name}`, `おかえりなさい、${name}`,
`おかえりなさいませっ、${name}っ。` `おかえりなさいませっ、${name}っ。`,
] : [ ] : [
'おかえりなさい♪', 'おかえりなさい♪',
'おかえりなさいませっ、ご主人様っ。' 'おかえりなさいませっ、ご主人様っ。',
], ],
love2: name => name ? `おかえりなさいませ♡♡♡${name}っっ♡♡♡♡♡` : 'おかえりなさいませ♡♡♡ご主人様っっ♡♡♡♡♡', love2: (name) => name ? `おかえりなさいませ♡♡♡${name}っっ♡♡♡♡♡` : 'おかえりなさいませ♡♡♡ご主人様っっ♡♡♡♡♡',
normal: name => name ? `おかえりなさい、${name}` : 'おかえりなさい!', normal: (name) => name ? `おかえりなさい、${name}` : 'おかえりなさい!',
}, },
itterassyai: { itterassyai: {
love: name => name ? `いってらっしゃい、${name}` : 'いってらっしゃい♪', love: (name) => name ? `いってらっしゃい、${name}` : 'いってらっしゃい♪',
normal: name => name ? `いってらっしゃい、${name}` : 'いってらっしゃい!', normal: (name) => name ? `いってらっしゃい、${name}` : 'いってらっしゃい!',
}, },
tooLong: '長すぎる気がします...', tooLong: '長すぎる気がします...',
@ -97,15 +97,15 @@ export default {
love: ['嬉しいです♪', '照れちゃいます...'], love: ['嬉しいです♪', '照れちゃいます...'],
hate: '…ありがとうございます' hate: '…ありがとうございます',
}, },
suki: { suki: {
normal: 'えっ… ありがとうございます…♪', normal: 'えっ… ありがとうございます…♪',
love: name => `私もその… ${name}のこと好きですよ!`, love: (name) => `私もその… ${name}のこと好きですよ!`,
hate: null hate: null,
}, },
hug: { hug: {
@ -113,7 +113,7 @@ export default {
love: 'ぎゅーっ♪', love: 'ぎゅーっ♪',
hate: '離れてください...' hate: '離れてください...',
}, },
humu: { humu: {
@ -121,7 +121,7 @@ export default {
normal: 'えぇ... それはちょっと...', normal: 'えぇ... それはちょっと...',
hate: '……' hate: '……',
}, },
batou: { batou: {
@ -129,10 +129,10 @@ export default {
normal: '(じとー…)', normal: '(じとー…)',
hate: '…頭大丈夫ですか?' hate: '…頭大丈夫ですか?',
}, },
itai: name => name ? `${name}、大丈夫ですか…? いたいのいたいの飛んでけっ!` : '大丈夫ですか…? いたいのいたいの飛んでけっ!', itai: (name) => name ? `${name}、大丈夫ですか…? いたいのいたいの飛んでけっ!` : '大丈夫ですか…? いたいのいたいの飛んでけっ!',
ote: { ote: {
normal: 'くぅん... 私わんちゃんじゃないですよ...', normal: 'くぅん... 私わんちゃんじゃないですよ...',
@ -146,25 +146,25 @@ export default {
transferNeedDm: 'わかりました、それはチャットで話しませんか?', transferNeedDm: 'わかりました、それはチャットで話しませんか?',
transferCode: code => `わかりました。\n合言葉は「${code}」です!`, transferCode: (code) => `わかりました。\n合言葉は「${code}」です!`,
transferFailed: 'うーん、合言葉が間違ってませんか...', transferFailed: 'うーん、合言葉が間違ってませんか...',
transferDone: name => name ? `はっ... おかえりなさい、${name}` : `はっ... おかえりなさい!`, transferDone: (name) => name ? `はっ... おかえりなさい、${name}` : `はっ... おかえりなさい!`,
}, },
keyword: { keyword: {
learned: (word, reading) => `(${word}..... ${reading}..... 覚えました)`, learned: (word, reading) => `(${word}..... ${reading}..... 覚えました)`,
remembered: (word) => `${word}` remembered: (word) => `${word}`,
}, },
dice: { dice: {
done: res => `${res} です!` done: (res) => `${res} です!`,
}, },
birthday: { birthday: {
happyBirthday: name => name ? `お誕生日おめでとうございます、${name}🎉` : 'お誕生日おめでとうございます🎉', happyBirthday: (name) => name ? `お誕生日おめでとうございます、${name}🎉` : 'お誕生日おめでとうございます🎉',
}, },
/** /**
@ -189,47 +189,47 @@ export default {
/** /**
* *
*/ */
startedSettai: name => `(${name}の接待を始めました)`, startedSettai: (name) => `(${name}の接待を始めました)`,
/** /**
* *
*/ */
iWon: name => `${name}に勝ちました♪`, iWon: (name) => `${name}に勝ちました♪`,
/** /**
* *
*/ */
iWonButSettai: name => `(${name}に接待で勝っちゃいました...)`, iWonButSettai: (name) => `(${name}に接待で勝っちゃいました...)`,
/** /**
* *
*/ */
iLose: name => `${name}に負けました...`, iLose: (name) => `${name}に負けました...`,
/** /**
* *
*/ */
iLoseButSettai: name => `(${name}に接待で負けてあげました...♪)`, iLoseButSettai: (name) => `(${name}に接待で負けてあげました...♪)`,
/** /**
* *
*/ */
drawn: name => `${name}と引き分けました~`, drawn: (name) => `${name}と引き分けました~`,
/** /**
* *
*/ */
drawnSettai: name => `(${name}に接待で引き分けました...)`, drawnSettai: (name) => `(${name}に接待で引き分けました...)`,
/** /**
* *
*/ */
youSurrendered: name => `${name}が投了しちゃいました`, youSurrendered: (name) => `${name}が投了しちゃいました`,
/** /**
* *
*/ */
settaiButYouSurrendered: name => `(${name}を接待していたら投了されちゃいました... ごめんなさい)`, settaiButYouSurrendered: (name) => `(${name}を接待していたら投了されちゃいました... ごめんなさい)`,
}, },
/** /**
@ -264,27 +264,27 @@ export default {
/** /**
* *
*/ */
grater: num => `${num}より大きいですね`, grater: (num) => `${num}より大きいですね`,
/** /**
* (2) * (2)
*/ */
graterAgain: num => `もう一度言いますが${num}より大きいですよ!`, graterAgain: (num) => `もう一度言いますが${num}より大きいですよ!`,
/** /**
* *
*/ */
less: num => `${num}より小さいですね`, less: (num) => `${num}より小さいですね`,
/** /**
* (2) * (2)
*/ */
lessAgain: num => `もう一度言いますが${num}より小さいですよ!`, lessAgain: (num) => `もう一度言いますが${num}より小さいですよ!`,
/** /**
* *
*/ */
congrats: tries => `正解です🎉 (${tries}回目で当てました)`, congrats: (tries) => `正解です🎉 (${tries}回目で当てました)`,
}, },
/** /**
@ -295,7 +295,7 @@ export default {
matakondo: 'また今度やりましょう!', matakondo: 'また今度やりましょう!',
intro: minutes => `みなさん、数取りゲームしましょう!\n0~100の中で最も大きい数字を取った人が勝ちです。他の人と被ったらだめですよ\n制限時間は${minutes}分です。数字はこの投稿にリプライで送ってくださいね!`, intro: (minutes) => `みなさん、数取りゲームしましょう!\n0~100の中で最も大きい数字を取った人が勝ちです。他の人と被ったらだめですよ\n制限時間は${minutes}分です。数字はこの投稿にリプライで送ってくださいね!`,
finish: 'ゲームの結果発表です!', finish: 'ゲームの結果発表です!',
@ -303,21 +303,21 @@ export default {
finishWithNoWinner: '今回は勝者はいませんでした... またやりましょう♪', finishWithNoWinner: '今回は勝者はいませんでした... またやりましょう♪',
onagare: '参加者が集まらなかったのでお流れになりました...' onagare: '参加者が集まらなかったのでお流れになりました...',
}, },
/** /**
* *
*/ */
emoji: { emoji: {
suggest: emoji => `こんなのはどうですか?→${emoji}`, suggest: (emoji) => `こんなのはどうですか?→${emoji}`,
}, },
/** /**
* *
*/ */
fortune: { fortune: {
cw: name => name ? `私が今日の${name}の運勢を占いました...` : '私が今日のあなたの運勢を占いました...', cw: (name) => name ? `私が今日の${name}の運勢を占いました...` : '私が今日のあなたの運勢を占いました...',
}, },
/** /**
@ -330,7 +330,7 @@ export default {
tooLong: '長すぎます…', tooLong: '長すぎます…',
notify: (time, name) => name ? `${name}${time}経ちましたよ!` : `${time}経ちましたよ!` notify: (time, name) => name ? `${name}${time}経ちましたよ!` : `${time}経ちましたよ!`,
}, },
/** /**
@ -341,7 +341,7 @@ export default {
doneFromInvalidUser: 'イタズラはめっですよ!', doneFromInvalidUser: 'イタズラはめっですよ!',
invalidVisibility: "公開範囲の指定を変えてみて", invalidVisibility: '公開範囲の指定を変えてみて',
reminds: 'やること一覧です!', reminds: 'やること一覧です!',
@ -366,25 +366,25 @@ export default {
* *
*/ */
valentine: { valentine: {
chocolateForYou: name => name ? `${name}、その... チョコレート作ったのでよかったらどうぞ!🍫` : 'チョコレート作ったのでよかったらどうぞ!🍫', chocolateForYou: (name) => name ? `${name}、その... チョコレート作ったのでよかったらどうぞ!🍫` : 'チョコレート作ったのでよかったらどうぞ!🍫',
}, },
server: { server: {
cpu: 'サーバーの負荷が高そうです。大丈夫でしょうか...' cpu: 'サーバーの負荷が高そうです。大丈夫でしょうか...',
}, },
maze: { maze: {
post: '今日の迷路です! #2na2Maze', post: '今日の迷路です! #2na2Maze',
foryou: '描きました!' foryou: '描きました!',
}, },
chart: { chart: {
post: 'インスタンスの投稿数です!', post: 'インスタンスの投稿数です!',
foryou: '描きました!' foryou: '描きました!',
}, },
sleepReport: { sleepReport: {
report: hours => `んぅ、${hours}時間くらい寝ちゃってたみたいです`, report: (hours) => `んぅ、${hours}時間くらい寝ちゃってたみたいです`,
reportUtatane: 'ん... うたた寝しちゃってました', reportUtatane: 'ん... うたた寝しちゃってました',
}, },
@ -466,9 +466,9 @@ export default {
'じー', 'じー',
'はにゃ?', 'はにゃ?',
], ],
want: item => `${item}、欲しいなぁ...`, want: (item) => `${item}、欲しいなぁ...`,
see: item => `お散歩していたら、道に${item}が落ちているのを見たんです!`, see: (item) => `お散歩していたら、道に${item}が落ちているのを見たんです!`,
expire: item => `気づいたら、${item}の賞味期限が切れてました…`, expire: (item) => `気づいたら、${item}の賞味期限が切れてました…`,
}, },
}; };

View file

@ -22,7 +22,7 @@ export default class Stream extends EventEmitter {
this.buffer = []; this.buffer = [];
this.stream = new ReconnectingWebsocket(`${config.wsUrl}/streaming?i=${config.i}`, [], { this.stream = new ReconnectingWebsocket(`${config.wsUrl}/streaming?i=${config.i}`, [], {
WebSocket: WebSocket WebSocket: WebSocket,
}); });
this.stream.addEventListener('open', this.onOpen); this.stream.addEventListener('open', this.onOpen);
this.stream.addEventListener('close', this.onClose); this.stream.addEventListener('close', this.onClose);
@ -31,7 +31,7 @@ export default class Stream extends EventEmitter {
@autobind @autobind
public useSharedConnection(channel: string): SharedConnection { public useSharedConnection(channel: string): SharedConnection {
let pool = this.sharedConnectionPools.find(p => p.channel === channel); let pool = this.sharedConnectionPools.find((p) => p.channel === channel);
if (pool == null) { if (pool == null) {
pool = new Pool(this, channel); pool = new Pool(this, channel);
@ -45,7 +45,7 @@ export default class Stream extends EventEmitter {
@autobind @autobind
public removeSharedConnection(connection: SharedConnection) { public removeSharedConnection(connection: SharedConnection) {
this.sharedConnections = this.sharedConnections.filter(c => c !== connection); this.sharedConnections = this.sharedConnections.filter((c) => c !== connection);
} }
@autobind @autobind
@ -57,7 +57,7 @@ export default class Stream extends EventEmitter {
@autobind @autobind
public disconnectToChannel(connection: NonSharedConnection) { public disconnectToChannel(connection: NonSharedConnection) {
this.nonSharedConnections = this.nonSharedConnections.filter(c => c !== connection); this.nonSharedConnections = this.nonSharedConnections.filter((c) => c !== connection);
} }
/** /**
@ -79,10 +79,10 @@ export default class Stream extends EventEmitter {
// チャンネル再接続 // チャンネル再接続
if (isReconnect) { if (isReconnect) {
this.sharedConnectionPools.forEach(p => { this.sharedConnectionPools.forEach((p) => {
p.connect(); p.connect();
}); });
this.nonSharedConnections.forEach(c => { this.nonSharedConnections.forEach((c) => {
c.connect(); c.connect();
}); });
} }
@ -109,13 +109,13 @@ export default class Stream extends EventEmitter {
let connections: (Connection | undefined)[]; let connections: (Connection | undefined)[];
connections = this.sharedConnections.filter(c => c.id === id); connections = this.sharedConnections.filter((c) => c.id === id);
if (connections.length === 0) { if (connections.length === 0) {
connections = [this.nonSharedConnections.find(c => c.id === id)]; connections = [this.nonSharedConnections.find((c) => c.id === id)];
} }
for (const c of connections.filter(c => c != null)) { for (const c of connections.filter((c) => c != null)) {
c!.emit(body.type, body.body); c!.emit(body.type, body.body);
c!.emit('*', {type: body.type, body: body.body}); c!.emit('*', {type: body.type, body: body.body});
} }
@ -132,7 +132,7 @@ export default class Stream extends EventEmitter {
public send(typeOrPayload, payload?) { public send(typeOrPayload, payload?) {
const data = payload === undefined ? typeOrPayload : { const data = payload === undefined ? typeOrPayload : {
type: typeOrPayload, type: typeOrPayload,
body: payload body: payload,
}; };
// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する
@ -203,7 +203,7 @@ class Pool {
this.isConnected = true; this.isConnected = true;
this.stream.send('connect', { this.stream.send('connect', {
channel: this.channel, channel: this.channel,
id: this.id id: this.id,
}); });
} }
@ -235,7 +235,7 @@ abstract class Connection extends EventEmitter {
this.stream.send('ch', { this.stream.send('ch', {
id: id, id: id,
type: type, type: type,
body: body body: body,
}); });
} }
@ -287,7 +287,7 @@ class NonSharedConnection extends Connection {
this.stream.send('connect', { this.stream.send('connect', {
channel: this.channel, channel: this.channel,
id: this.id, id: this.id,
params: this.params params: this.params,
}); });
} }

View file

@ -1,5 +1,5 @@
export function acct(user: { username: string; host?: string | null; }): string { export function acct(user: { username: string; host?: string | null; }): string {
return user.host return user.host ?
? `@${user.username}@${user.host}` `@${user.username}@${user.host}` :
: `@${user.username}`; `@${user.username}`;
} }

View file

@ -4,7 +4,7 @@ export default function(text: string, words: string[]): boolean {
if (text == null) return false; if (text == null) return false;
text = katakanaToHiragana(hankakuToZenkaku(text)).toLowerCase(); text = katakanaToHiragana(hankakuToZenkaku(text)).toLowerCase();
words = words.map(word => katakanaToHiragana(word).toLowerCase()); words = words.map((word) => katakanaToHiragana(word).toLowerCase());
return words.some(word => text.includes(word)); return words.some((word) => text.includes(word));
} }

View file

@ -19,16 +19,16 @@ const kanaMap: string[][] = [
['ワ', 'ワ'], ['ヲ', 'ヲ'], ['ン', 'ン'], ['ワ', 'ワ'], ['ヲ', 'ヲ'], ['ン', 'ン'],
['ァ', 'ァ'], ['ィ', 'ィ'], ['ゥ', 'ゥ'], ['ェ', 'ェ'], ['ォ', 'ォ'], ['ァ', 'ァ'], ['ィ', 'ィ'], ['ゥ', 'ゥ'], ['ェ', 'ェ'], ['ォ', 'ォ'],
['ッ', 'ッ'], ['ャ', 'ャ'], ['ュ', 'ュ'], ['ョ', 'ョ'], ['ッ', 'ッ'], ['ャ', 'ャ'], ['ュ', 'ュ'], ['ョ', 'ョ'],
['ー', 'ー'] ['ー', 'ー'],
]; ];
/** /**
* *
* @param str * @param str
* @returns * @return
*/ */
export function katakanaToHiragana(str: string): string { export function katakanaToHiragana(str: string): string {
return str.replace(/[\u30a1-\u30f6]/g, match => { return str.replace(/[\u30a1-\u30f6]/g, (match) => {
const char = match.charCodeAt(0) - 0x60; const char = match.charCodeAt(0) - 0x60;
return String.fromCharCode(char); return String.fromCharCode(char);
}); });
@ -37,10 +37,10 @@ export function katakanaToHiragana(str: string): string {
/** /**
* *
* @param str * @param str
* @returns * @return
*/ */
export function hiraganaToKatagana(str: string): string { export function hiraganaToKatagana(str: string): string {
return str.replace(/[\u3041-\u3096]/g, match => { return str.replace(/[\u3041-\u3096]/g, (match) => {
const char = match.charCodeAt(0) + 0x60; const char = match.charCodeAt(0) + 0x60;
return String.fromCharCode(char); return String.fromCharCode(char);
}); });
@ -49,14 +49,14 @@ export function hiraganaToKatagana(str: string): string {
/** /**
* *
* @param str * @param str
* @returns * @return
*/ */
export function zenkakuToHankaku(str: string): string { export function zenkakuToHankaku(str: string): string {
const reg = new RegExp('(' + kanaMap.map(x => x[0]).join('|') + ')', 'g'); const reg = new RegExp('(' + kanaMap.map((x) => x[0]).join('|') + ')', 'g');
return str return str
.replace(reg, match => .replace(reg, (match) =>
kanaMap.find(x => x[0] == match)![1] kanaMap.find((x) => x[0] == match)![1],
) )
.replace(/゛/g, '゙') .replace(/゛/g, '゙')
.replace(/゜/g, '゚'); .replace(/゜/g, '゚');
@ -65,14 +65,14 @@ export function zenkakuToHankaku(str: string): string {
/** /**
* *
* @param str * @param str
* @returns * @return
*/ */
export function hankakuToZenkaku(str: string): string { export function hankakuToZenkaku(str: string): string {
const reg = new RegExp('(' + kanaMap.map(x => x[1]).join('|') + ')', 'g'); const reg = new RegExp('(' + kanaMap.map((x) => x[1]).join('|') + ')', 'g');
return str return str
.replace(reg, match => .replace(reg, (match) =>
kanaMap.find(x => x[1] == match)![0] kanaMap.find((x) => x[1] == match)![0],
) )
.replace(/゙/g, '゛') .replace(/゙/g, '゛')
.replace(/゚/g, '゜'); .replace(/゚/g, '゜');

View file

@ -4,9 +4,9 @@ export default function(text: string, words: (string | RegExp)[]): boolean {
if (text == null) return false; if (text == null) return false;
text = katakanaToHiragana(hankakuToZenkaku(text)); text = katakanaToHiragana(hankakuToZenkaku(text));
words = words.map(word => typeof word == 'string' ? katakanaToHiragana(word) : word); words = words.map((word) => typeof word == 'string' ? katakanaToHiragana(word) : word);
return words.some(word => { return words.some((word) => {
/** /**
* *
* *

View file

@ -12,5 +12,5 @@ const invalidChars = [
]; ];
export function safeForInterpolate(text: string): boolean { export function safeForInterpolate(text: string): boolean {
return !invalidChars.some(c => text.includes(c)); return !invalidChars.some((c) => text.includes(c));
} }

View file

@ -459,11 +459,11 @@ export const and = [
]; ];
export function genItem(seedOrRng?: (() => number) | string | number) { export function genItem(seedOrRng?: (() => number) | string | number) {
const rng = seedOrRng const rng = seedOrRng ?
? typeof seedOrRng === 'function' typeof seedOrRng === 'function' ?
? seedOrRng seedOrRng :
: seedrandom(seedOrRng.toString()) seedrandom(seedOrRng.toString()) :
: Math.random; Math.random;
let item = ''; let item = '';
if (Math.floor(rng() * 5) !== 0) item += itemPrefixes[Math.floor(rng() * itemPrefixes.length)]; if (Math.floor(rng() * 5) !== 0) item += itemPrefixes[Math.floor(rng() * itemPrefixes.length)];

View file

@ -12,7 +12,7 @@ export class Misskey {
this.server = http.createServer(app.callback()); this.server = http.createServer(app.callback());
const ws = new websocket.server({ const ws = new websocket.server({
httpServer: this.server httpServer: this.server,
}); });
ws.on('request', async (request) => { ws.on('request', async (request) => {
@ -40,7 +40,7 @@ export class Misskey {
} }
public async waitForMainChannelConnected() { public async waitForMainChannelConnected() {
await this.waitForStreamingMessage(message => { await this.waitForStreamingMessage((message) => {
const {type, body} = message; const {type, body} = message;
if (type === 'connect') { if (type === 'connect') {
const {channel, id, params, pong} = body; const {channel, id, params, pong} = body;
@ -49,7 +49,7 @@ export class Misskey {
if (pong) { if (pong) {
this.sendStreamingMessage('connected', { this.sendStreamingMessage('connected', {
id: id id: id,
}); });
} }
@ -61,7 +61,7 @@ export class Misskey {
public sendStreamingMessage(type: string, payload: any) { public sendStreamingMessage(type: string, payload: any) {
this.streaming.send(JSON.stringify({ this.streaming.send(JSON.stringify({
type: type, type: type,
body: payload body: payload,
})); }));
} }
} }

View file

@ -8,7 +8,7 @@ export class StreamingApi {
} }
public async waitForMainChannelConnected() { public async waitForMainChannelConnected() {
await expect(this.ws).toReceiveMessage("hello"); await expect(this.ws).toReceiveMessage('hello');
} }
public send(message) { public send(message) {

View file

@ -8,7 +8,7 @@ export default class extends Module {
@autobind @autobind
public install() { public install() {
return { return {
mentionHook: this.mentionHook mentionHook: this.mentionHook,
}; };
} }
@ -16,7 +16,7 @@ export default class extends Module {
private async mentionHook(msg: Message) { private async mentionHook(msg: Message) {
if (msg.text && msg.text.includes('ping')) { if (msg.text && msg.text.includes('ping')) {
msg.reply('PONG!', { msg.reply('PONG!', {
immediate: true immediate: true,
}); });
return true; return true;
} else { } else {

View file

@ -15,6 +15,4 @@ beforeEach(() => {
test('mention hook', async () => { test('mention hook', async () => {
const streaming = new StreamingApi(); const streaming = new StreamingApi();
}); });

5641
yarn.lock Normal file

File diff suppressed because it is too large Load diff