nanka iroiro

Closes #3
This commit is contained in:
syuilo 2018-08-27 20:22:59 +09:00
parent 87f6729c98
commit 5bbd348c08
5 changed files with 229 additions and 42 deletions

View file

@ -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
View 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);
}
}

View file

@ -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,23 +27,22 @@ 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) => {
console.log(`sending reply of ${this.id} ...`); console.log(`sending reply of ${this.id} ...`);

View file

@ -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,12 +15,60 @@ 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);
}
/**
* ()
*/
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 birthFriends = this.ai.friends.find({
'user.profile.birthday': { '$regex': new RegExp('-' + today + '$') }
} as any);
birthFriends.forEach(f => {
const friend = new Friend(this.ai, { doc: f });
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;
}
const name = msg.text.match(/^(.+?)って呼んで/)[1]; const name = msg.text.match(/^(.+?)って呼んで/)[1];
if (name.length > 10) { if (name.length > 10) {
@ -31,8 +84,7 @@ export default class CoreModule implements IModule {
name.endsWith('様'); name.endsWith('様');
if (withSan) { if (withSan) {
msg.friend.name = name; msg.friend.updateName(name);
this.ai.friends.update(msg.friend);
msg.reply(serifs.core.setNameOk.replace('{name}', name)); msg.reply(serifs.core.setNameOk.replace('{name}', name));
} else { } else {
msg.reply(serifs.core.san).then(reply => { msg.reply(serifs.core.san).then(reply => {
@ -43,13 +95,37 @@ export default class CoreModule implements IModule {
} }
return true; return true;
} else if (msg.text.includes('おはよう')) { }
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 => {

View file

@ -7,7 +7,10 @@ export default {
goodMorningWithName: 'おはようございます、{name}', goodMorningWithName: 'おはようございます、{name}',
goodNight: 'おやすみなさい!', goodNight: 'おやすみなさい!',
goodNightWithName: 'おやすみなさい、{name}', goodNightWithName: 'おやすみなさい、{name}',
tooLong: '長すぎる気がします...' tooLong: '長すぎる気がします...',
requireMoreLove: 'もっと仲良くなったら考えてあげてもいいですよ?',
happyBirthday: 'お誕生日おめでとうございます🎉',
happyBirthdayWithName: 'お誕生日おめでとうございます、{name}🎉'
}, },
keyword: { keyword: {