mirror of
https://github.com/syuilo/ai.git
synced 2024-11-22 13:17:59 +00:00
parent
87f6729c98
commit
5bbd348c08
|
@ -3,10 +3,10 @@
|
||||||
import * as loki from 'lokijs';
|
import * as loki from 'lokijs';
|
||||||
import * as WebSocket from 'ws';
|
import * as WebSocket from 'ws';
|
||||||
import * as request from 'request-promise-native';
|
import * as request from 'request-promise-native';
|
||||||
import serifs from './serifs';
|
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import IModule from './module';
|
import IModule from './module';
|
||||||
import MessageLike from './message-like';
|
import MessageLike from './message-like';
|
||||||
|
import { FriendDoc } from './friend';
|
||||||
const ReconnectingWebSocket = require('../node_modules/reconnecting-websocket/dist/reconnecting-websocket-cjs.js');
|
const ReconnectingWebSocket = require('../node_modules/reconnecting-websocket/dist/reconnecting-websocket-cjs.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,10 +38,7 @@ export default class 藍 {
|
||||||
data?: any;
|
data?: any;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
public friends: loki.Collection<{
|
public friends: loki.Collection<FriendDoc>;
|
||||||
userId: string;
|
|
||||||
name?: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
constructor(account: any) {
|
constructor(account: any) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
|
110
src/friend.ts
Normal file
110
src/friend.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import 藍 from './ai';
|
||||||
|
import IModule from './module';
|
||||||
|
|
||||||
|
export type FriendDoc = {
|
||||||
|
userId: string;
|
||||||
|
user: any;
|
||||||
|
name?: string;
|
||||||
|
love?: number;
|
||||||
|
lastLoveIncrementedAt?: string;
|
||||||
|
todayLoveIncrements?: number;
|
||||||
|
perModulesData?: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Friend {
|
||||||
|
private ai: 藍;
|
||||||
|
|
||||||
|
public get userId() {
|
||||||
|
return this.doc.userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get name() {
|
||||||
|
return this.doc.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get love() {
|
||||||
|
return this.doc.love || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public doc: FriendDoc;
|
||||||
|
|
||||||
|
constructor(ai: 藍, opts: { user?: any, doc?: FriendDoc }) {
|
||||||
|
this.ai = ai;
|
||||||
|
|
||||||
|
if (opts.user) {
|
||||||
|
this.doc = this.ai.friends.findOne({
|
||||||
|
userId: opts.user.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.doc == null) {
|
||||||
|
this.doc = this.ai.friends.insertOne({
|
||||||
|
userId: opts.user.id,
|
||||||
|
user: opts.user
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.doc.user = opts.user;
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.doc = opts.doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateUser = (user: any) => {
|
||||||
|
this.doc.user = user;
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPerModulesData = (module: IModule) => {
|
||||||
|
if (this.doc.perModulesData == null) {
|
||||||
|
this.doc.perModulesData = {};
|
||||||
|
this.doc.perModulesData[module.name] = {};
|
||||||
|
this.save();
|
||||||
|
} else if (this.doc.perModulesData[module.name] == null) {
|
||||||
|
this.doc.perModulesData[module.name] = {};
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.doc.perModulesData[module.name];
|
||||||
|
}
|
||||||
|
|
||||||
|
public setPerModulesData = (module: IModule, data: any) => {
|
||||||
|
if (this.doc.perModulesData == null) {
|
||||||
|
this.doc.perModulesData = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doc.perModulesData[module.name] = data;
|
||||||
|
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public incLove = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const y = now.getFullYear();
|
||||||
|
const m = now.getMonth();
|
||||||
|
const d = now.getDate();
|
||||||
|
const today = `${y}/${m + 1}/${d}`;
|
||||||
|
|
||||||
|
if (this.doc.lastLoveIncrementedAt != today) {
|
||||||
|
this.doc.todayLoveIncrements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1日に上げられる親愛度は最大3
|
||||||
|
if (this.doc.lastLoveIncrementedAt == today && this.doc.todayLoveIncrements >= 3) return;
|
||||||
|
|
||||||
|
if (this.doc.love == null) this.doc.love = 0;
|
||||||
|
this.doc.love++;
|
||||||
|
this.doc.lastLoveIncrementedAt = today;
|
||||||
|
this.doc.todayLoveIncrements = (this.doc.todayLoveIncrements || 0) + 1;
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateName = (name: string) => {
|
||||||
|
this.doc.name = name;
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public save = () => {
|
||||||
|
this.ai.friends.update(this.doc);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import 藍 from './ai';
|
import 藍 from './ai';
|
||||||
|
import Friend from './friend';
|
||||||
const delay = require('timeout-as-promise');
|
const delay = require('timeout-as-promise');
|
||||||
|
|
||||||
export default class MessageLike {
|
export default class MessageLike {
|
||||||
|
@ -26,22 +27,21 @@ export default class MessageLike {
|
||||||
return this.messageOrNote.replyId;
|
return this.messageOrNote.replyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public friend: ReturnType<藍['friends']['findOne']>;
|
public friend: Friend;
|
||||||
|
|
||||||
constructor(ai: 藍, messageOrNote: any, isMessage: boolean) {
|
constructor(ai: 藍, messageOrNote: any, isMessage: boolean) {
|
||||||
this.ai = ai;
|
this.ai = ai;
|
||||||
this.messageOrNote = messageOrNote;
|
this.messageOrNote = messageOrNote;
|
||||||
this.isMessage = isMessage;
|
this.isMessage = isMessage;
|
||||||
|
|
||||||
this.friend = this.ai.friends.findOne({
|
this.friend = new Friend(ai, { user: this.user });
|
||||||
userId: this.userId
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.friend == null) {
|
// メッセージなどに付いているユーザー情報は省略されている場合があるので完全なユーザー情報を持ってくる
|
||||||
this.friend = this.ai.friends.insertOne({
|
this.ai.api('users/show', {
|
||||||
userId: this.userId
|
userId: this.userId
|
||||||
});
|
}).then(user => {
|
||||||
}
|
this.friend.updateUser(user);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public reply = async (text: string, cw?: string) => {
|
public reply = async (text: string, cw?: string) => {
|
||||||
|
|
|
@ -3,6 +3,11 @@ import 藍 from '../../ai';
|
||||||
import IModule from '../../module';
|
import IModule from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
|
import Friend from '../../friend';
|
||||||
|
|
||||||
|
function zeroPadding(num: number, length: number): string {
|
||||||
|
return ('0000000000' + num).slice(-length);
|
||||||
|
}
|
||||||
|
|
||||||
export default class CoreModule implements IModule {
|
export default class CoreModule implements IModule {
|
||||||
public name = 'core';
|
public name = 'core';
|
||||||
|
@ -10,46 +15,117 @@ export default class CoreModule implements IModule {
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
public install = (ai: 藍) => {
|
||||||
this.ai = ai;
|
this.ai = ai;
|
||||||
|
|
||||||
|
this.crawleBirthday();
|
||||||
|
setInterval(this.crawleBirthday, 1000 * 60 * 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
public onMention = (msg: MessageLike) => {
|
||||||
if (!msg.text) return false;
|
if (!msg.text) return false;
|
||||||
|
|
||||||
if (msg.text.includes('って呼んで') && !msg.text.startsWith('って呼んで')) {
|
return this.setName(msg) || this.greet(msg);
|
||||||
const name = msg.text.match(/^(.+?)って呼んで/)[1];
|
}
|
||||||
|
|
||||||
if (name.length > 10) {
|
/**
|
||||||
msg.reply(serifs.core.tooLong);
|
* 誕生日のユーザーがいないかチェック(いたら祝う)
|
||||||
return true;
|
*/
|
||||||
}
|
private crawleBirthday = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const y = now.getFullYear();
|
||||||
|
const m = now.getMonth();
|
||||||
|
const d = now.getDate();
|
||||||
|
// Misskeyの誕生日は 2018-06-16 のような形式
|
||||||
|
const today = `${zeroPadding(m + 1, 2)}-${d}`;
|
||||||
|
|
||||||
const withSan =
|
const birthFriends = this.ai.friends.find({
|
||||||
name.endsWith('さん') ||
|
'user.profile.birthday': { '$regex': new RegExp('-' + today + '$') }
|
||||||
name.endsWith('くん') ||
|
} as any);
|
||||||
name.endsWith('君') ||
|
|
||||||
name.endsWith('ちゃん') ||
|
|
||||||
name.endsWith('様');
|
|
||||||
|
|
||||||
if (withSan) {
|
birthFriends.forEach(f => {
|
||||||
msg.friend.name = name;
|
const friend = new Friend(this.ai, { doc: f });
|
||||||
this.ai.friends.update(msg.friend);
|
|
||||||
msg.reply(serifs.core.setNameOk.replace('{name}', name));
|
|
||||||
} else {
|
|
||||||
msg.reply(serifs.core.san).then(reply => {
|
|
||||||
this.ai.subscribeReply(this, msg.userId, msg.isMessage, msg.isMessage ? msg.userId : reply.id, {
|
|
||||||
name: name
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const data = friend.getPerModulesData(this);
|
||||||
|
|
||||||
|
if (data.lastBirthdayChecked == today) return;
|
||||||
|
|
||||||
|
data.lastBirthdayChecked = today;
|
||||||
|
friend.setPerModulesData(this, data);
|
||||||
|
|
||||||
|
const text = friend.name ? serifs.core.happyBirthdayWithName.replace('{name}', friend.name) : serifs.core.happyBirthday;
|
||||||
|
|
||||||
|
this.ai.sendMessage(friend.userId, {
|
||||||
|
text: text
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private setName = (msg: MessageLike): boolean => {
|
||||||
|
if (!msg.text) return false;
|
||||||
|
if (!msg.text.includes('って呼んで')) return false;
|
||||||
|
if (msg.text.startsWith('って呼んで')) return false;
|
||||||
|
|
||||||
|
if (msg.friend.love < 5) {
|
||||||
|
msg.reply(serifs.core.requireMoreLove);
|
||||||
return true;
|
return true;
|
||||||
} else if (msg.text.includes('おはよう')) {
|
}
|
||||||
|
|
||||||
|
const name = msg.text.match(/^(.+?)って呼んで/)[1];
|
||||||
|
|
||||||
|
if (name.length > 10) {
|
||||||
|
msg.reply(serifs.core.tooLong);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const withSan =
|
||||||
|
name.endsWith('さん') ||
|
||||||
|
name.endsWith('くん') ||
|
||||||
|
name.endsWith('君') ||
|
||||||
|
name.endsWith('ちゃん') ||
|
||||||
|
name.endsWith('様');
|
||||||
|
|
||||||
|
if (withSan) {
|
||||||
|
msg.friend.updateName(name);
|
||||||
|
msg.reply(serifs.core.setNameOk.replace('{name}', name));
|
||||||
|
} else {
|
||||||
|
msg.reply(serifs.core.san).then(reply => {
|
||||||
|
this.ai.subscribeReply(this, msg.userId, msg.isMessage, msg.isMessage ? msg.userId : reply.id, {
|
||||||
|
name: name
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private greet = (msg: MessageLike): boolean => {
|
||||||
|
if (!msg.text) return false;
|
||||||
|
|
||||||
|
const incLove = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const y = now.getFullYear();
|
||||||
|
const m = now.getMonth();
|
||||||
|
const d = now.getDate();
|
||||||
|
const date = `${y}/${m + 1}/${d}`;
|
||||||
|
|
||||||
|
const data = msg.friend.getPerModulesData(this);
|
||||||
|
|
||||||
|
if (data.lastGreetedAt == date) return;
|
||||||
|
|
||||||
|
data.lastGreetedAt = date;
|
||||||
|
msg.friend.setPerModulesData(this, data);
|
||||||
|
|
||||||
|
msg.friend.incLove();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (msg.text.includes('おはよう')) {
|
||||||
if (msg.friend.name) {
|
if (msg.friend.name) {
|
||||||
msg.reply(serifs.core.goodMorningWithName.replace('{name}', msg.friend.name));
|
msg.reply(serifs.core.goodMorningWithName.replace('{name}', msg.friend.name));
|
||||||
} else {
|
} else {
|
||||||
msg.reply(serifs.core.goodMorning);
|
msg.reply(serifs.core.goodMorning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incLove();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (msg.text.includes('おやすみ')) {
|
} else if (msg.text.includes('おやすみ')) {
|
||||||
if (msg.friend.name) {
|
if (msg.friend.name) {
|
||||||
|
@ -58,6 +134,8 @@ export default class CoreModule implements IModule {
|
||||||
msg.reply(serifs.core.goodNight);
|
msg.reply(serifs.core.goodNight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incLove();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -68,16 +146,15 @@ export default class CoreModule implements IModule {
|
||||||
if (msg.text == null) return;
|
if (msg.text == null) return;
|
||||||
|
|
||||||
const done = () => {
|
const done = () => {
|
||||||
this.ai.friends.update(msg.friend);
|
|
||||||
msg.reply(serifs.core.setNameOk.replace('{name}', msg.friend.name));
|
msg.reply(serifs.core.setNameOk.replace('{name}', msg.friend.name));
|
||||||
this.ai.unsubscribeReply(this, msg.userId);
|
this.ai.unsubscribeReply(this, msg.userId);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (msg.text.includes('はい')) {
|
if (msg.text.includes('はい')) {
|
||||||
msg.friend.name = data.name + 'さん';
|
msg.friend.updateName(data.name + 'さん');
|
||||||
done();
|
done();
|
||||||
} else if (msg.text.includes('いいえ')) {
|
} else if (msg.text.includes('いいえ')) {
|
||||||
msg.friend.name = 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 => {
|
||||||
|
|
|
@ -7,7 +7,10 @@ export default {
|
||||||
goodMorningWithName: 'おはようございます、{name}!',
|
goodMorningWithName: 'おはようございます、{name}!',
|
||||||
goodNight: 'おやすみなさい!',
|
goodNight: 'おやすみなさい!',
|
||||||
goodNightWithName: 'おやすみなさい、{name}!',
|
goodNightWithName: 'おやすみなさい、{name}!',
|
||||||
tooLong: '長すぎる気がします...'
|
tooLong: '長すぎる気がします...',
|
||||||
|
requireMoreLove: 'もっと仲良くなったら考えてあげてもいいですよ?',
|
||||||
|
happyBirthday: 'お誕生日おめでとうございます🎉',
|
||||||
|
happyBirthdayWithName: 'お誕生日おめでとうございます、{name}🎉'
|
||||||
},
|
},
|
||||||
|
|
||||||
keyword: {
|
keyword: {
|
||||||
|
|
Loading…
Reference in a new issue