diff --git a/Dockerfile_production b/Dockerfile_production index 1973ae1..1351d50 100644 --- a/Dockerfile_production +++ b/Dockerfile_production @@ -17,9 +17,9 @@ RUN if [ $enable_mecab -ne 0 ]; then apt-get update \ && echo "dicdir = /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd/" > /etc/mecabrc \ && apt-get purge git make curl xz-utils file -y; fi -COPY ../NullcatChan-old /nullcat-chan +COPY . /NullcatChan -WORKDIR /nullcat-chan +WORKDIR /NullcatChan RUN npm install && npm run build ENTRYPOINT ["/usr/bin/tini", "--"] diff --git a/docker-compose.yml b/docker-compose.yml index ff36f08..534c856 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: app: build: dockerfile: Dockerfile_production - context: ../NullcatChan-old + context: ../NullcatChan args: - enable_mecab=1 volumes: diff --git a/package.json b/package.json index 6b5d0d3..38baf46 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "version": "2.1.0", "main": "./built/index.js", "scripts": { - "docker:dev": "cross-env DOCKER_ENV=development docker-compose -f docker-compose.yml -f docker-compose_development.yml up -d --build && docker-compose logs -f", - "docker": "cross-env DOCKER_ENV=production docker-compose up -d --build && docker-compose logs -f", + "docker:dev": "cross-env DOCKER_ENV=development docker compose -f docker-compose.yml -f docker-compose_development.yml up -d --build && docker compose logs -f", + "docker": "cross-env DOCKER_ENV=production docker compose up -d --build && docker compose logs -f", "dev": "cross-env NODE_ENV=development node ./built", "start": "cross-env NODE_ENV=production node ./built", "build": "tsc", @@ -25,7 +25,7 @@ "@types/ws": "7.4.6", "accurate-interval": "1.0.9", "autobind-decorator": "2.4.0", - "canvas": "2.8.0", + "canvas": "2.11.0", "chalk": "4.1.1", "cjp": "1.2.3", "gomamayo-js": "0.2.1", diff --git a/src/friend.ts b/src/friend.ts index 24d5cfa..fec554e 100644 --- a/src/friend.ts +++ b/src/friend.ts @@ -1,8 +1,8 @@ import { User } from "./misskey/user" -import IModule from "../../NullcatChan-old/src/module" -import NullcatChan from "../../NullcatChan-old/src/nullcat-chan" -import getDate from "../../NullcatChan-old/src/utils/get-date" -import { genItem } from "../../NullcatChan-old/src/vocabulary" +import IModule from "../../NullcatChan/src/module" +import NullcatChan from "../../NullcatChan/src/nullcat-chan" +import getDate from "../../NullcatChan/src/utils/get-date" +import { genItem } from "../../NullcatChan/src/vocabulary" import autobind from "autobind-decorator" export type FriendDoc = { diff --git a/src/index.ts b/src/index.ts index 6672b2c..94f2b34 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,109 +1,107 @@ -// Nullcat chan! bootstrapper - -import * as chalk from "chalk" -import "module-alias/register" -import * as request from "request-promise-native" -import config from "./config" -import BirthdayModule from "../../NullcatChan-old/src/modules/birthday" -import CoreModule from "../../NullcatChan-old/src/modules/core" -import EmojiReactModule from "../../NullcatChan-old/src/modules/emoji-react" -import FeelingModule from "../../NullcatChan-old/src/modules/feeling" -import FollowModule from "../../NullcatChan-old/src/modules/follow" -import FortuneModule from "../../NullcatChan-old/src/modules/fortune" -import GitHubStatusModule from "../../NullcatChan-old/src/modules/github-status" -import CloudflareStatus from "../../NullcatChan-old/src/modules/cloudflare-status"; -import GomamayoModule from "../../NullcatChan-old/src/modules/gomamayo" -import JihouModule from "../../NullcatChan-old/src/modules/jihou" -import KeywordModule from "../../NullcatChan-old/src/modules/keyword" -import KiatsuModule from "../../NullcatChan-old/src/modules/kiatsu" -import NotingModule from "../../NullcatChan-old/src/modules/noting" -import PingModule from "../../NullcatChan-old/src/modules/ping" -import ReminderModule from "../../NullcatChan-old/src/modules/reminder" -import RoguboModule from "../../NullcatChan-old/src/modules/rogubo" -import ServerModule from "../../NullcatChan-old/src/modules/server" -import SleepReportModule from "../../NullcatChan-old/src/modules/sleep-report" -import TalkModule from "../../NullcatChan-old/src/modules/talk" -import TimerModule from "../../NullcatChan-old/src/modules/timer" -import TraceMoeModule from "../../NullcatChan-old/src/modules/trace-moe" -import ValentineModule from "../../NullcatChan-old/src/modules/valentine" -import WhatModule from "../../NullcatChan-old/src/modules/what" -import YarukotoModule from "../../NullcatChan-old/src/modules/yarukoto" -import NullcatChan from "../../NullcatChan-old/src/nullcat-chan" -import _log from "../../NullcatChan-old/src/utils/log" -import ShellGeiModule from "../../NullcatChan-old/src/modules/shellgei" -import SversionModule from "../../NullcatChan-old/src/modules/Sversion" -import AyashiiModule from "../../NullcatChan-old/src/modules/ayashii" - -const promiseRetry = require("promise-retry") - -const pkg = require("../../NullcatChan-old/package.json") - -console.log(" _ __ ____ __ ________ __ ") -console.log(" / | / /_ __/ / /________ _/ /_/ ____/ /_ ____ _____ / / ") -console.log(" / |/ / / / / / / ___/ __ `/ __/ / / __ \\/ __ `/ __ \\/ / ") -console.log(" / /| / /_/ / / / /__/ /_/ / /_/ /___/ / / / /_/ / / / /_/ ") -console.log("/_/ |_/\\__,_/_/_/\\___/\\__,_/\\__/\\____/_/ /_/\\__,_/_/ /_(_)\n") - -function log(msg: string): void { - _log(`[Boot]: ${msg}`) -} - -log(chalk.bold(`Nullcat chan! v${pkg._v}`)) - -promiseRetry( - (retry) => { - log(`Account fetching... ${chalk.gray(config.host)}`) - - // アカウントをフェッチ - return request - .post(`${config.apiUrl}/i`, { - json: { - i: config.i, - }, - }) - .catch(retry) - }, - { - retries: 3, - } -) - .then((account) => { - const acct = `@${account.username}` - log(chalk.green(`Account fetched successfully: ${chalk.underline(acct)}`)) - - log("Starting Nullcat chan...") - - // ぬるきゃっとちゃん起動 - new NullcatChan(account, [ - new CoreModule(), - new EmojiReactModule(), - new FortuneModule(), - new TimerModule(), - new TalkModule(), - new FollowModule(), - new BirthdayModule(), - new ValentineModule(), - new KeywordModule(), - new SleepReportModule(), - new NotingModule(), - new ReminderModule(), - new GomamayoModule(), - new GitHubStatusModule(), - new CloudflareStatus(), - new YarukotoModule(), - new RoguboModule(), - new KiatsuModule(), - new JihouModule(), - new WhatModule(), - new FeelingModule(), - new TraceMoeModule(), - new ServerModule(), - new ShellGeiModule(), - new SversionModule(), - new AyashiiModule(), - new PingModule(), - ]) - }) - .catch((e) => { - log(chalk.red("Failed to fetch the account")) - }) +// Nullcat chan! bootstrapper + +import * as chalk from "chalk" +import "module-alias/register" +import * as request from "request-promise-native" +import config from "./config" +import BirthdayModule from "../../NullcatChan/src/modules/birthday" +import CoreModule from "../../NullcatChan/src/modules/core" +import EmojiReactModule from "../../NullcatChan/src/modules/emoji-react" +import FeelingModule from "../../NullcatChan/src/modules/feeling" +import FollowModule from "../../NullcatChan/src/modules/follow" +import FortuneModule from "../../NullcatChan/src/modules/fortune" +import GitHubStatusModule from "../../NullcatChan/src/modules/github-status" +import CloudflareStatus from "../../NullcatChan/src/modules/cloudflare-status"; +import GomamayoModule from "../../NullcatChan/src/modules/gomamayo" +import JihouModule from "../../NullcatChan/src/modules/jihou" +import KeywordModule from "../../NullcatChan/src/modules/keyword" +import KiatsuModule from "../../NullcatChan/src/modules/kiatsu" +import NotingModule from "../../NullcatChan/src/modules/noting" +import PingModule from "../../NullcatChan/src/modules/ping" +import ReminderModule from "../../NullcatChan/src/modules/reminder" +import ServerModule from "../../NullcatChan/src/modules/server" +import SleepReportModule from "../../NullcatChan/src/modules/sleep-report" +import TalkModule from "../../NullcatChan/src/modules/talk" +import TimerModule from "../../NullcatChan/src/modules/timer" +import TraceMoeModule from "../../NullcatChan/src/modules/trace-moe" +import ValentineModule from "../../NullcatChan/src/modules/valentine" +import WhatModule from "../../NullcatChan/src/modules/what" +import YarukotoModule from "../../NullcatChan/src/modules/yarukoto" +import NullcatChan from "../../NullcatChan/src/nullcat-chan" +import _log from "../../NullcatChan/src/utils/log" +import ShellGeiModule from "../../NullcatChan/src/modules/shellgei" +import SversionModule from "../../NullcatChan/src/modules/version" +import AyashiiModule from "../../NullcatChan/src/modules/ayashii" + +const promiseRetry = require("promise-retry") + +const pkg = require("../../NullcatChan/package.json") + +console.log(" _ __ ____ __ ________ __ ") +console.log(" / | / /_ __/ / /________ _/ /_/ ____/ /_ ____ _____ / / ") +console.log(" / |/ / / / / / / ___/ __ `/ __/ / / __ \\/ __ `/ __ \\/ / ") +console.log(" / /| / /_/ / / / /__/ /_/ / /_/ /___/ / / / /_/ / / / /_/ ") +console.log("/_/ |_/\\__,_/_/_/\\___/\\__,_/\\__/\\____/_/ /_/\\__,_/_/ /_(_)\n") + +function log(msg: string): void { + _log(`[Boot]: ${msg}`) +} + +log(chalk.bold(`Nullcat chan! v${pkg._v}`)) + +promiseRetry( + (retry) => { + log(`Account fetching... ${chalk.gray(config.host)}`) + + // アカウントをフェッチ + return request + .post(`${config.apiUrl}/i`, { + json: { + i: config.i, + }, + }) + .catch(retry) + }, + { + retries: 3, + } +) + .then((account) => { + const acct = `@${account.username}` + log(chalk.green(`Account fetched successfully: ${chalk.underline(acct)}`)) + + log("Starting Nullcat chan...") + + // ぬるきゃっとちゃん起動 + new NullcatChan(account, [ + new CoreModule(), + new EmojiReactModule(), + new FortuneModule(), + new TimerModule(), + new TalkModule(), + new FollowModule(), + new BirthdayModule(), + new ValentineModule(), + new KeywordModule(), + new SleepReportModule(), + new NotingModule(), + new ReminderModule(), + new GomamayoModule(), + new GitHubStatusModule(), + new CloudflareStatus(), + new YarukotoModule(), + new KiatsuModule(), + new JihouModule(), + new WhatModule(), + new FeelingModule(), + new TraceMoeModule(), + new ServerModule(), + new ShellGeiModule(), + new SversionModule(), + new AyashiiModule(), + new PingModule(), + ]) + }) + .catch((e) => { + log(chalk.red("Failed to fetch the account")) + }) diff --git a/src/message.ts b/src/message.ts index aa834f4..e66a706 100644 --- a/src/message.ts +++ b/src/message.ts @@ -1,9 +1,9 @@ import config from "@/config" import Friend from "@/friend" import { User } from "./misskey/user" -import NullcatChan from "../../NullcatChan-old/src/nullcat-chan" -import includes from "../../NullcatChan-old/src/utils/includes" -import or from "../../NullcatChan-old/src/utils/or" +import NullcatChan from "../../NullcatChan/src/nullcat-chan" +import includes from "../../NullcatChan/src/utils/includes" +import or from "../../NullcatChan/src/utils/or" import autobind from "autobind-decorator" import * as chalk from "chalk" const delay = require("timeout-as-promise") diff --git a/src/module.ts b/src/module.ts index eba8209..1d05e9a 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,4 +1,4 @@ -import NullcatChan, { InstallerResult } from "./nullcat-chan" +import NullcatChan, { InstallerResult } from "@/nullcat-chan" import autobind from "autobind-decorator" export default abstract class Module { diff --git a/src/modules/cloudflare-status/index.ts b/src/modules/cloudflare-status/index.ts new file mode 100644 index 0000000..78b272c --- /dev/null +++ b/src/modules/cloudflare-status/index.ts @@ -0,0 +1,61 @@ +import config from '@/config'; +import Message from '@/message'; +import Module from '@/module'; +import autobind from 'autobind-decorator'; +import fetch from 'node-fetch'; +import { z } from 'zod'; + +export default class extends Module { + public readonly name = 'cloudflare-status'; + + private readonly schema = z.object({ + status: z.object({ + description: z.string(), + indicator: z.enum(['none', 'minor', 'major', 'critical']) + }) + }); + + private indicator: z.infer['status']['indicator'] = 'none'; + private description: z.infer['status']['description'] = ''; + + @autobind + public install() { + setInterval(this.updateStatus, 10 * 60 * 1000); + this.updateStatus(); + + return { + mentionHook: this.mentionHook + }; + } + + @autobind + private async updateStatus() { + try { + const response = await fetch('https://www.cloudflarestatus.com/api/v2/status.json'); + const data = await response.json(); + + const result = this.schema.safeParse(data); + + if (result.success) { + this.indicator = result.data.status.indicator; + this.description = result.data.status.description; + } else { + this.log('Validation failed.'); + console.warn(result.error); + } + } catch (error) { + this.log('Failed to fetch status from Cloudflare.'); + console.warn(error); + } + } + + @autobind + private async mentionHook(msg: Message) { + if (msg.text?.toLowerCase().includes('cloudflare')) { + msg.reply(`いまのCloudflareのステータスだよ!\n\nじょうきょう: ${this.indicator}\nせつめい: ${this.description}\nhttps://www.cloudflarestatus.com`); + return true; + } else { + return false; + } + } +} diff --git a/src/modules/core/index.ts b/src/modules/core/index.ts index 5a2a674..764b5c3 100644 --- a/src/modules/core/index.ts +++ b/src/modules/core/index.ts @@ -1,7 +1,7 @@ import Message from "@/message" import Module from "@/module" import serifs from "@/serifs" -import { safeForInterpolate } from "../../../../NullcatChan-old/src/utils/safe-for-interpolate" +import { safeForInterpolate } from "../../../../NullcatChan/src/utils/safe-for-interpolate" import autobind from "autobind-decorator" const titles = ["さん", "くん", "君", "ちゃん", "様", "先生"] diff --git a/src/modules/emoji-react/index.ts b/src/modules/emoji-react/index.ts index a420154..652be53 100644 --- a/src/modules/emoji-react/index.ts +++ b/src/modules/emoji-react/index.ts @@ -1,7 +1,7 @@ import { Note } from "../../misskey/note" import Module from "@/module" import Stream from "@/stream" -import includes from "../../../../NullcatChan-old/src/utils/includes" +import includes from "../../../../NullcatChan/src/utils/includes" import autobind from "autobind-decorator" const delay = require("timeout-as-promise") diff --git a/src/modules/reminder/index.ts b/src/modules/reminder/index.ts index d3027aa..b770151 100644 --- a/src/modules/reminder/index.ts +++ b/src/modules/reminder/index.ts @@ -2,7 +2,7 @@ import config from "@/config" import Message from "@/message" import Module from "@/module" import serifs, { getSerif } from "@/serifs" -import { acct } from "../../../../NullcatChan-old/src/utils/acct" +import { acct } from "../../../../NullcatChan/src/utils/acct" import autobind from "autobind-decorator" import * as loki from "lokijs" diff --git a/src/modules/talk/index.ts b/src/modules/talk/index.ts index d437700..dffcdb4 100644 --- a/src/modules/talk/index.ts +++ b/src/modules/talk/index.ts @@ -1,8 +1,8 @@ import Message from "@/message" import Module from "@/module" -import { HandlerResult } from "../../nullcat-chan" +import { HandlerResult } from "@/nullcat-chan" import serifs, { getSerif } from "@/serifs" -import getDate from "../../../../NullcatChan-old/src/utils/get-date" +import getDate from "../../../../NullcatChan/src/utils/get-date" import autobind from "autobind-decorator" export default class extends Module { diff --git a/src/modules/version/index.ts b/src/modules/version/index.ts new file mode 100644 index 0000000..fcda4a5 --- /dev/null +++ b/src/modules/version/index.ts @@ -0,0 +1,101 @@ +import autobind from 'autobind-decorator'; +import Module from '@/module'; +import Message from '@/message'; +/** + * バージョン情報 + */ +interface Version { + /** + * サーバーバージョン(meta.Sversion) + */ + server: string; + /** + * クライアントバージョン(meta.clientVersion) + */ + client: string; +} + +export default class extends Module { + public readonly name = 'version'; + + private latest?: Version; + + @autobind + public install() { + this.versionCheck(); + setInterval(this.versionCheck, 1000 * 60 * 60 * 1); + + return { + mentionHook: this.mentionHook + }; + } + + public versionCheck = () => { + // バージョンチェック + this.getVersion() + .then(fetched => { + this.log(`Version fetched: ${JSON.stringify(fetched)}`); + + if (this.latest != null && fetched != null) { + const serverChanged = this.latest.server !== fetched.server; + + if (serverChanged) { + let v = ''; + v += (serverChanged ? '**' : '') + `${this.latest.server} → ${this.mfmVersion(fetched.server)}\n` + (serverChanged ? '**' : ''); + + this.log(`Version changed: ${v}`); + + this.nullcatChan.post({ text: `ぼくのおうちが${v}にリフォームされたよ!!` }); + } else { + // 変更なし + } + } + + this.latest = fetched; + }) + .catch(e => this.log(`warn: ${e}`)); + }; + + @autobind + private async mentionHook(msg: Message) { + if (msg.text == null) return false; + + const query = msg.text.match(/サーバーバージョン/); + + if (query == null) return false; + + this.nullcatChan + .api('meta') + .then(meta => { + msg.reply(`${this.mfmVersion(meta.version)} みたいだよ!`); + }) + .catch(() => { + msg.reply(`取得失敗しちゃった:cry_nullcatchan:`); + }); + + return true; + } + + /** + * バージョンを取得する + */ + private getVersion = (): Promise => { + return this.nullcatChan.api('meta').then(meta => { + return { + server: meta.version, + client: meta.clientVersion + }; + }); + }; + + private mfmVersion = (v): string => { + if (v == null) return v; + return v.match(/^\d+\.\d+\.\d+$/) ? `[${v}](https://github.com/syuilo/misskey/releases/tag/${v})` : v; + }; + + private wait = (ms: number): Promise => { + return new Promise(resolve => { + setTimeout(() => resolve(), ms); + }); + }; +} diff --git a/src/ng-words.ts b/src/ng-words.ts index f4de16b..1a91af3 100644 --- a/src/ng-words.ts +++ b/src/ng-words.ts @@ -1,4 +1,4 @@ -import toHiragana from '../../NullcatChan-old/src/utils/to-hiragana'; +import toHiragana from '../../NullcatChan/src/utils/to-hiragana'; const fs = require('fs'); const readline = require('readline'); diff --git a/src/nullcat-chan.ts b/src/nullcat-chan.ts index 05d3d16..1c1aaa6 100644 --- a/src/nullcat-chan.ts +++ b/src/nullcat-chan.ts @@ -4,9 +4,9 @@ import config from "./config" import Friend, { FriendDoc } from "./friend" import Message from "./message" import { User } from "./misskey/user" -import Module from "../../NullcatChan-old/src/module" +import Module from "../../NullcatChan/src/module" import Stream from "./stream" -import log from "../../NullcatChan-old/src/utils/log" +import log from "../../NullcatChan/src/utils/log" import autobind from "autobind-decorator" import * as chalk from "chalk" import * as fs from "fs" @@ -15,7 +15,7 @@ import * as request from "request-promise-native" import { v4 as uuid } from "uuid" const delay = require("timeout-as-promise") -const pkg = require("../../NullcatChan-old/package.json") +const pkg = require("../../NullcatChan/package.json") type MentionHook = (msg: Message) => Promise type ContextHook = (key: any, msg: Message, data?: any) => Promise diff --git a/utils/acct.ts b/src/utils/acct.ts similarity index 100% rename from utils/acct.ts rename to src/utils/acct.ts diff --git a/utils/get-date.ts b/src/utils/get-date.ts similarity index 100% rename from utils/get-date.ts rename to src/utils/get-date.ts diff --git a/utils/includes.ts b/src/utils/includes.ts similarity index 100% rename from utils/includes.ts rename to src/utils/includes.ts diff --git a/utils/japanese.ts b/src/utils/japanese.ts similarity index 100% rename from utils/japanese.ts rename to src/utils/japanese.ts diff --git a/utils/log.ts b/src/utils/log.ts similarity index 100% rename from utils/log.ts rename to src/utils/log.ts diff --git a/utils/or.ts b/src/utils/or.ts similarity index 100% rename from utils/or.ts rename to src/utils/or.ts diff --git a/utils/safe-for-interpolate.ts b/src/utils/safe-for-interpolate.ts similarity index 100% rename from utils/safe-for-interpolate.ts rename to src/utils/safe-for-interpolate.ts diff --git a/src/utils/to-hiragana.ts b/src/utils/to-hiragana.ts new file mode 100644 index 0000000..0f108f1 --- /dev/null +++ b/src/utils/to-hiragana.ts @@ -0,0 +1,5 @@ +const moji = require('moji'); + +export default function toHiragana(str: string): string { + return moji(str).convert('HK', 'ZK').convert('KK', 'HG').toString(); +} diff --git a/tsconfig.json b/tsconfig.json index 8134fd1..694ae6c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "noLib": false, "outDir": "built", "rootDir": "src", - "baseUrl": "../NullcatChan-old", + "baseUrl": "../NullcatChan", "paths": { "@/*": ["src/*"] }