v7.3@uwuzu1.5.4をリリース

This commit is contained in:
Last2014 2025-08-04 20:08:23 +09:00
parent 718e97ed45
commit 6ec9831ed4
15 changed files with 353 additions and 42 deletions

2
data/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -17,6 +17,7 @@ const config: configTypes = {
areasCsvUrl: "https://raw.githubusercontent.com/p2pquake/epsp-specifications/master/epsp-area.csv", // 対象地域CSVファイルのURL
maxScaleMin: 30, // 地震発生の際の最低震度(10-70)
},
// 天気お知らせ設定
weather: {
splitCount: 4, // 返信の分割数
},
@ -35,10 +36,23 @@ const config: configTypes = {
to: "admin@noticeuwuzu.example.com", // 緊急時メール送信先(配列可)
},
},
// 規約等
legal: {
terms: `
`, // 利用規約
privacy: `
`, // プライバシーポリシー
},
// 管理者情報設定
admin: {
name: "あどみん", // BOT管理者名
showMail: true, // メールアドレスを公開するか(emergency.mail.toが使用されます)
},
// uwuzuサーバー設定
uwuzu: {
apiToken: "TOKEN_EXAMPLE",
clientToken: "TOKEN_EXAMPLE",
host: "uwuzu.example.com",
apiToken: "TOKEN_EXAMPLE", // APIトークン
clientToken: "TOKEN_EXAMPLE", // クライアントトークン(任意)
host: "uwuzu.example.com", // サーバーホスト(HTTPSである必要があります)
},
};

View File

@ -11,13 +11,16 @@ import * as cron from "node-cron";
import timeNotice from "./scripts/timeNotice.js";
import { weatherNotice } from "./scripts/weatherNotice.js";
import earthquakeNotice from "./scripts/earthquakeNotice.js";
import birthdayNotice from "./scripts/birthdayNotice.js";
import Commands from "./scripts/commands/main.js";
import BirthdayDataSet from "./scripts/birthdayDataSet.js";
// その他機能
import asciiArt from "./scripts/asciiart.js";
asciiArt();
import successExit from "./scripts/successExit.js";
successExit();
BirthdayDataSet();
// 地震情報観測開始
earthquakeNotice();
@ -27,6 +30,8 @@ cron.schedule("0 * * * *", () => {
timeNotice();
});
birthdayNotice();
// コマンド(10分/1回)
cron.schedule('*/10 * * * *', () => {
Commands();
@ -34,7 +39,10 @@ cron.schedule('*/10 * * * *', () => {
// 天気お知らせ(毎日7:00)
cron.schedule("0 7 * * *", () => {
setTimeout(() => {
weatherNotice();
birthdayNotice();
}, 100);
});
// 起動表示

View File

@ -1,7 +1,7 @@
{
"name": "notice-uwuzu",
"version": "v7.2@uwuzu1.5.4",
"tag": "v7.2",
"version": "v7.3@uwuzu1.5.4",
"tag": "v7.3",
"description": "Notice Bot for uwuzu",
"main": "dist/main.js",
"scripts": {
@ -20,15 +20,19 @@
"bot",
"cron",
"notice",
"mail",
"weather",
"time",
"earthquake"
"earthquake",
"command",
"commands"
],
"author": {
"name": "Last2014",
"url": "https://last2014.com",
"email": "info@last2014.com"
},
"contributors": [],
"license": "Apache-2.0",
"type": "module",
"dependencies": {

View File

@ -0,0 +1,14 @@
import { existsSync, writeFileSync } from "fs";
const initialData = {} as
{ [key: string]: string | undefined };
export default function BirthdayDataSet() {
if (!existsSync("data/birthdays.json")) {
writeFileSync(
"data/birthdays.json",
JSON.stringify(initialData),
"utf-8",
);
}
}

56
scripts/birthdayNotice.ts Normal file
View File

@ -0,0 +1,56 @@
import { readFileSync } from "fs";
import { isSameDay, format, differenceInYears } from "date-fns/fp";
import config from "../config.js";
export default async function birthdayNotice() {
// 読み込み
const birthdays: { [key: string]: string | undefined } =
JSON.parse(readFileSync("data/birthdays.json", "utf-8"));
// 配列化
const birthdaysIndex: string[] = Object.entries(birthdays)
.map(([key, value]) => value)
.filter(value => value !== undefined) as string[];
// 初期値
const resultInitial: string = `
\n`;
let result = resultInitial;
for (let i = 0; i < Object.keys(birthdays).length; i++) {
const birthday = format(birthdaysIndex[i], "yyyy/MM/dd")
if (isSameDay(birthday, new Date())) {
const age = differenceInYears(new Date(), birthday);
const req = await fetch(`https://${config.uwuzu.host}/api/users/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
userid: Object.keys(birthdays)[i],
}),
});
const res = await req.json();
result+= `${res.username}さん(${age}歳)\n`
}
}
if (result === resultInitial) {
return;
}
const req = await fetch(`https://${config.uwuzu.host}/api/ueuse/create`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
text: result,
}),
});
const res = await req.json();
console.log("誕生日お知らせ:", res);
}

View File

@ -0,0 +1,88 @@
import { ueuse } from "types/types.js";
import { readFileSync, writeFileSync, existsSync } from "fs";
import { parse, isValid } from 'date-fns/fp';
import { Reply } from "./main.js";
function normalizedString(Str: string) {
return Str.replace(/[\u3000-\u303F]+/g, ' ')
.replace(/[\uFF01-\uFF0F]+/g, '0-9')
.replace(/[\u3001-\u3002]+/g, '/');
}
function isValidDateString(dateString: string) {
const normalizedStr = normalizedString(dateString);
const regex = /^\d{4}\/\d{2}\/\d{2}$/;
if (!regex.test(normalizedStr)) {
return false;
}
const parseString = parse(new Date(), 'yyyy/MM/dd');
return isValid(parseString(normalizedStr));
}
export default function Birthday(data: ueuse) {
// 読み込み
const birthdays: { [key: string]: string | undefined } =
JSON.parse(readFileSync("data/birthdays.json", "utf-8"));
if (
(data.abi === "none" ||
data.abi === "") &&
birthdays[data.account.userid] === undefined
) {
Reply(`
(\`/birthday\`をまたご利用ください。)
`, data.uniqid);
return;
}
if (
data.abi === "delete" &&
birthdays[data.account.userid] !== undefined
) {
birthdays[data.account.userid] = undefined;
writeFileSync(
"data/birthdays.json",
JSON.stringify(birthdays),
"utf-8",
);
Reply(`
`, data.uniqid);
return;
}
if (
data.abi === "delete" &&
birthdays[data.account.userid] === undefined
) {
Reply(`
`, data.uniqid);
return;
}
if (!isValidDateString(data.abi)) {
Reply(`
yyyy/MM/ddの形式で入力してください
使
(\`/birthday\`をまたご利用ください。)
`, data.uniqid);
return;
}
birthdays[data.account.userid] = normalizedString(data.abi);
writeFileSync(
"data/birthdays.json",
JSON.stringify(birthdays),
"utf-8",
);
Reply(`
${data.account.username}${normalizedString(data.abi)}
`, data.uniqid);
}

View File

@ -2,27 +2,81 @@ import { ueuse } from "types/types.js";
import { readFileSync } from "fs";
import { Reply } from "./main.js";
const helps = {
const helpsMin = {
"info": "このBOTについての概要を返信するコマンドです。",
"help": "このコマンドです。コマンドの概要を返信します。",
"help": "コマンドの概要を返信します。追記に\`/\`抜きのコマンド名を入力することでそのコマンドの詳細(フル)を返信します。",
"follow": "コマンド送信者をフォローします。",
"unfollow": "コマンド送信者をフォロー解除します。",
"weather": "天気を返信します。7:00に投稿されるものとは異なり再取得します。",
"weather": "天気を返信します。",
"report": "運営者に不具合などを報告します。",
"birthday": "誕生日を設定・削除できます。",
"legal privacy": "プライバシーポリシーを返信します。",
} as { [key: string]: string };
const helpsFull = {
"info": `
BOTについての概要を返信するコマンドです
`,
"help": `
\`/\`抜きのコマンド名を入力することでそのコマンドの詳細(フル)を返信します。
`,
"follow": `
使
`,
"unfollow": `
使
`,
"weather": `
毎日7:00の天気を再投稿するわけではなく
`,
"report": `
使
\`/report\`を使用してそのユーズの追記に内容を入力することで使用できます。
`,
"birthday": `
設定された誕生日の7:00に祝われます
yyyy/MM/ddの形式で誕生日を入力することで誕生日を設定できます
\`delete\`と入力することで誕生日のデータを削除できます。
`,
"legal privacy": `
`,
} as { [key: string]: string };
export default async function Help(data: ueuse) {
const packageJson = JSON.parse(readFileSync("package.json", "utf-8"));
if (
data.abi === "none" ||
data.abi === ""
) {
const helpMsg =
Object.entries(helps)
Object.entries(helpsMin)
.map(([command, message]) =>
`\`/${command}\`${message}`
).join('\n');
const ueuse = await Reply(`
${helpMsg}
BOTの概要は\`/info\`をご利用ください。
Wikiを見る${packageJson.repository.url}/wiki
`, data.uniqid);
console.log("ヘルプ:", ueuse);
} else {
const ueuse = await Reply(`
${helpsFull[data.abi]}
${packageJson.repository.url}/wiki
`, data.uniqid);
console.log("ヘルプ:", ueuse);
}
}

View File

@ -1,6 +1,7 @@
import { ueuse } from "types/types.js";
import { readFileSync } from "fs";
import { Reply } from "./main.js";
import config from "../../config.js";
export default async function Info(data: ueuse) {
const packageJson = JSON.parse(readFileSync("package.json", "utf-8"));
@ -12,13 +13,56 @@ export default async function Info(data: ueuse) {
editor = `\nEdited by ${packageJson.author.name}`;
}
let adminMail;
if (
config.admin.showMail &&
config.emergency.mail.to !== undefined
) {
adminMail = config.emergency.mail.to;
} else if (
config.admin.showMail &&
config.emergency.mail.to === undefined
) {
adminMail = "未設定";
} else {
adminMail = "非公開";
}
let isReport;
if (config.emergency.report) {
isReport = "有効";
} else {
isReport = "無効";
}
const ueuse = await Reply(`
BOTについて
BOTはオープンソースソフトウェアであるnoticeUwuzuを利用して運営されています
noticeUwuzuはApache License 2.0
使
${packageJson.version}
${releaseUrl}
${config.admin.name}
${adminMail}
(\`/report\`)${isReport}
\`/help\`をご利用ください。
\`/report\`をご利用ください。
\`/legal privacy\`をご利用ください。
Created by Last2014${editor}
`, data.uniqid);

View File

@ -0,0 +1,7 @@
import { ueuse } from "types/types.js";
import { Reply } from "../main.js";
import config from "../../../config.js";
export default function PrivacyPolicy(data: ueuse) {
Reply(config.legal.privacy, data.uniqid);
}

View File

@ -0,0 +1,7 @@
import { ueuse } from "types/types.js";
import { Reply } from "../main.js";
import config from "../../../config.js";
export default function Terms(data: ueuse) {
Reply(config.legal.terms, data.uniqid);
}

View File

@ -11,6 +11,9 @@ import UnFollow from "./unfollow.js";
import Weather from "./weather.js";
import Help from "./help.js";
import Report from "./report.js";
import Birthday from "./birthday.js";
import Terms from "./legal/terms.js"
import PrivacyPolicy from "./legal/privacy.js";
// 初期化
if (!fs.existsSync("logs/alreadyCommands.json")) {
@ -97,37 +100,39 @@ export default async function Commands() {
const commandName = cutAfterChar(data.text, "/");
alreadyAdd(data.uniqid);
switch (commandName) {
case "":
alreadyAdd(data.uniqid);
break;
case "info":
alreadyAdd(data.uniqid);
Info(data);
break;
case "help":
alreadyAdd(data.uniqid);
Help(data);
break;
case "legal terms":
Terms(data);
break;
case "legal privacy":
PrivacyPolicy(data);
break;
case "report":
alreadyAdd(data.uniqid);
Report(data);
break;
case "follow":
alreadyAdd(data.uniqid);
Follow(data);
break;
case "unfollow":
alreadyAdd(data.uniqid);
UnFollow(data);
break;
case "weather":
alreadyAdd(data.uniqid);
Weather(data);
break;
case "birthday":
Birthday(data);
break;
default:
alreadyAdd(data.uniqid);
const reply = await Reply(`
1\`!\`を入れてください。

View File

@ -1,6 +1,6 @@
import { ueuse } from "types/types.js";
import { Reply } from "./main.js";
import config from "config.js";
import config from "../../config.js";
import sendMail from "../../src/mailer.js";
export default async function Report(data: ueuse) {
@ -15,10 +15,6 @@ export default async function Report(data: ueuse) {
return;
}
if (data.abi === "ignore") {
return;
}
if (!config.emergency.mail.function) {
console.log("報告(メールオフ)", await Reply(`
BOTの運営者によってメール送信機能が無効化されています

View File

@ -1,5 +1,5 @@
import * as fs from "fs";
import { isBefore } from "date-fns/fp";
import { isAfter } from "date-fns";
import config from "../config.js";
import sendMail from "../src/mailer.js";
@ -20,7 +20,7 @@ export default function successExit() {
const start = iolog.start;
const stop = iolog.stop;
if (isBefore(start, stop)) {
if (isAfter(start, stop)) {
console.log("前回の終了が適切でない可能性があります");
if (config.emergency.mail.function) {

24
types/config.d.ts vendored
View File

@ -19,19 +19,29 @@ interface timeTypes {
}
interface emergencyMailTypes {
function: Boolean;
host: string | undefined;
function: boolean;
host: string;
port: number;
user: string;
password: string;
secure: Boolean;
to: string;
secure: boolean;
to: string | string[];
}
interface emergencyTypes {
function: Boolean;
function: boolean;
mail: emergencyMailTypes;
report: Boolean;
report: boolean;
}
interface legalTypes {
terms: string;
privacy: string;
}
interface adminTypes {
name: string;
showMail: boolean;
}
interface uwuzuTypes {
@ -46,5 +56,7 @@ export interface configTypes {
weather: weatherTypes;
emergency: emergencyTypes;
legal: legalTypes;
admin: adminTypes;
uwuzu: uwuzuTypes;
}