v7.0(unconfirmed)をリリース

This commit is contained in:
Last2014 2025-08-01 18:57:15 +09:00
parent 50db83cc8c
commit dc67845bc8
17 changed files with 317 additions and 115 deletions

View File

@ -4,7 +4,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,

View File

@ -1,21 +1,37 @@
# uwuzuお知らせBOT # noticeUwuzu
# uwuzuお知らせBOTについて # Overview
uwuzuで動作するお知らせBOTです。 Automatic notification bot for uwuzu
# 設定 # Functions
examples/config.tsをプロジェクトルートへ移動し各設定を更新してください。
# サーバー起動 - Time notification
- Earthquake information notification
- Earthquake Early Warning
- Earthquake occurs
- Tsunami forecast
- Weather notification
- Startup requirements check
- Check package existence
- Required package version check
- Check uwuzu API
- Check the configuration file
- Version change notification
- ASCII art at startup
- Confirm normal completion
``` # Config
An example configuration file is available in `examples/config.ts`.
# Start the server
```bash
npm install npm install
npm run build npm run build
npm run start npm run start
``` ```
Recommended Node.js version: v22.16.0
※Node.js・npmがインストールされている必要があります。 # License
[Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0)
# ライセンス
Apache 2.0 License

24
main.ts
View File

@ -9,33 +9,33 @@ import * as cron from "node-cron";
// 機能読み込み // 機能読み込み
import timeNotice from "./scripts/timeNotice.js"; import timeNotice from "./scripts/timeNotice.js";
import weatherNotice from "./scripts/weatherNotice.js"; import { weatherNotice } from "./scripts/weatherNotice.js";
import earthquakeNotice from "./scripts/earthquakeNotice.js"; import earthquakeNotice from "./scripts/earthquakeNotice.js";
import Commands from "scripts/commands/main.js";
// アスキーアート読み込み // その他機能
import asciiArt from "./scripts/asciiart.js"; import asciiArt from "./scripts/asciiart.js";
asciiArt(); asciiArt();
// フォロー機能読み込み
import follows from "./scripts/follow/main.js";
// 正常終了確認読み込み
import successExit from "./scripts/successExit.js"; import successExit from "./scripts/successExit.js";
successExit(); successExit();
// 地震情報観測開始 // 地震情報観測開始
earthquakeNotice(); earthquakeNotice();
/*// () // 時報(1時間/1回)
cron.schedule("0 * * * *", () => { cron.schedule("0 * * * *", () => {
timeNotice(); timeNotice();
follows();
}); });
// 天気お知らせ(毎日7:01) // コマンド(10分/1回)
cron.schedule("10 0 7 * * *", () => { cron.schedule('*/10 * * * *', () => {
Commands();
});
// 天気お知らせ(毎日7:00)
cron.schedule("0 7 * * *", () => {
weatherNotice(); weatherNotice();
});*/ });
// 起動表示 // 起動表示
console.log("BOTサーバーが起動しました"); console.log("BOTサーバーが起動しました");

View File

@ -1,13 +1,14 @@
{ {
"name": "notice-uwuzu", "name": "notice-uwuzu",
"version": "v6.5(LTS)@uwuzu1.5.4", "version": "v7.0(unconfirmed)@uwuzu1.5.4",
"description": "Notice Bot for uwuzu", "description": "Notice Bot for uwuzu",
"main": "dist/main.js", "main": "dist/main.js",
"scripts": { "scripts": {
"start": "node .", "start": "node .",
"build": "tsc", "build": "tsc",
"main": "tsc && node .", "main": "tsc && node .",
"dev": "tsx main.ts" "dev": "tsx main.ts",
"clean": "tsc && node dist/scripts/clean/main.js"
}, },
"keywords": [ "keywords": [
"uwuzu", "uwuzu",
@ -28,10 +29,11 @@
"dependencies": { "dependencies": {
"@types/date-fns": "^2.5.3", "@types/date-fns": "^2.5.3",
"@types/dotenv": "^6.1.1", "@types/dotenv": "^6.1.1",
"@types/node": "^24.0.7",
"@types/node-cron": "^3.0.11", "@types/node-cron": "^3.0.11",
"@types/nodemailer": "^6.4.17", "@types/nodemailer": "^6.4.17",
"@types/node": "^24.0.7",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"child_process": "^1.0.2",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"fs": "^0.0.1-security", "fs": "^0.0.1-security",
"node-cron": "^4.1.1", "node-cron": "^4.1.1",

16
scripts/clean/logsDel.ts Normal file
View File

@ -0,0 +1,16 @@
import { unlinkSync } from "fs";
export default function logsDelete() {
console.log("ログを削除中します");
try {
unlinkSync("logs/boot.json");
unlinkSync("logs/version.txt");
console.log("ログファイルを削除しました");
console.log("----------------");
} catch (err) {
console.log("ログファイルの削除中にエラーが発生しました:\n", err);
process.exit();
}
}

7
scripts/clean/main.ts Normal file
View File

@ -0,0 +1,7 @@
import logsDelete from "./logsDel.js";
import packageLockJsonDelete from "./packageLockDel.js";
import npmInstall from "./npmInstall.js";
logsDelete();
packageLockJsonDelete();
npmInstall();

View File

@ -0,0 +1,23 @@
import { execSync } from "child_process";
export default function npmInstall() {
// npm install実行
console.log("npm installを実行します");
try {
const npmInstall = execSync("npm install");
console.log("----");
console.log("$ npm install");
console.log(npmInstall.toString());
console.log("----");
console.log("npm installを実行しました");
} catch (err) {
console.log("npm installの実行中にエラーが発生しました:\n", err);
process.exit();
}
console.log("初期化が完了しました");
process.exit();
}

View File

@ -0,0 +1,15 @@
import { unlinkSync } from "fs";
export default function packageLockJsonDelete() {
console.log("package-lock.jsonを削除します");
try {
unlinkSync("package-lock.json");
console.log("package-lock.jsonを削除しました");
console.log("----------------");
} catch (err) {
console.log("package-lock.jsonの削除中にエラーが発生しました:\n", err);
process.exit();
}
}

View File

@ -0,0 +1,32 @@
import { ueuse } from "types/types.js";
import config from "../../config.js";
export default async function Follow(data: ueuse) {
const followReq = await fetch(`https://${config.uwuzu.host}/api/users/follow/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
userid: data.account.userid,
}),
});
const followRes = await followReq.json();
console.log("フォロー: ", followRes);
const noticeReq = await fetch(`https://${config.uwuzu.host}/api/ueuse/create/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
text: `
${data.account.username}
`,
replyid: data.uniqid,
}),
});
const noticeRes = await noticeReq.json();
console.log("フォロー通知: ", noticeRes);
}

114
scripts/commands/main.ts Normal file
View File

@ -0,0 +1,114 @@
import * as fs from "fs";
import config from "../../config.js";
import type { ueuse } from "types/types.js";
const initialFile: Array<string> = [];
// コマンド読み込み
import Follow from "./follow.js";
import UnFollow from "./unfollow.js";
import Weather from "./weather.js";
// 初期化
if (!fs.existsSync("logs/alreadyCommands.json")) {
fs.writeFileSync(
"logs/alreadyCommands.json",
JSON.stringify(initialFile),
"utf-8",
);
}
// 対応済みユーズ一覧
const alreadyCommands: Array<string> = JSON.parse(fs.readFileSync("alreadyCommands.json", "utf-8"));
function cutAfterChar(str: string, char: string) {
const index = str.indexOf(char);
if (index === -1) {
return "";
}
return str.substring(index + 1);
}
async function Reply(text: string, reply: string) {
const req = await fetch(`https://${config.uwuzu.host}/api/ueuse/create`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
text: text,
replyid: reply,
}),
});
const res = await req.json();
return res;
}
function alreadyAdd(data: string) {
alreadyCommands[alreadyCommands.length] = data;
fs.writeFileSync(
"logs/alreadyCommands.json",
JSON.stringify(alreadyCommands),
"utf-8",
);
}
export default async function Commands() {
const mentions: Array<ueuse> = await (await fetch(
`https://${config.uwuzu.host}/api/ueuse/mentions/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
}),
}
)).json();
console.log("----------------");
console.log("コマンド処理");
for (let i = 0; i < mentions.length; i++) {
const data = mentions[i];
// 除外ユーズ
if (alreadyCommands.indexOf(data.uniqid) !== -1) {
break;
}
if (data.text.charAt(0) === "!") {
break;
}
// コマンド処理
console.log("--------");
const commandName = cutAfterChar(data.text, "/");
switch (commandName) {
case "follow":
alreadyAdd(data.uniqid);
Follow(data);
break;
case "unfollow":
alreadyAdd(data.uniqid);
UnFollow(data);
break;
case "weather":
alreadyAdd(data.uniqid);
Weather(data);
break;
default:
alreadyAdd(data.uniqid);
const reply = await Reply(`
1\`!\`を入れてください。
`, data.uniqid);
console.log("未対応コマンド: ", reply);
break;
}
}
}

View File

@ -0,0 +1,31 @@
import { ueuse } from "types/types.js";
import config from "../../config.js";
export default async function UnFollow(data: ueuse) {
const unfollowReq = await fetch(`https://${config.uwuzu.host}/api/users/unfollow/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
userid: data.account.userid,
}),
});
const unfollowRes = await unfollowReq.json();
console.log("フォロー解除: ", unfollowRes);
const noticeReq = await fetch(`https://${config.uwuzu.host}/api/ueuse/create/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
text: `
${data.account.username}
`,
replyid: data.uniqid,
}),
});
const noticeRes = await noticeReq.json();
console.log("フォロー解除通知: ", noticeRes);
}

View File

@ -0,0 +1,6 @@
import { weatherReply } from "scripts/weatherNotice";
import { ueuse } from "types/types.js";
export default function Weather(data: ueuse) {
weatherReply(data.uniqid);
}

View File

@ -1,44 +0,0 @@
import type * as types from "types/types";
import config from "../../config.js";
export default async function followBack() {
console.log("----------------");
// フォロワーを取得
const resMe = await fetch(
`https://${config.uwuzu.host}/api/me/`,
{
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
}),
},
);
const meData: types.meApi = await resMe.json();
const followers = meData.follower;
// フォロー
for (let i = 0; i < followers.length; i++) {
const followerItem = followers[i];
setTimeout(async () => {
const resFollow = await fetch(
`https://${config.uwuzu.host}/api/users/follow/`,
{
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
userid: followerItem,
}),
},
);
const followData: types.followApi = await resFollow.json();
console.log(`フォロー:${JSON.stringify(followData)}`);
}, 100);
}
}

View File

@ -1,7 +0,0 @@
import followBack from "./follow.js";
import unFollowBack from "./unfollow.js";
export default function follows() {
unFollowBack();
followBack();
}

View File

@ -1,34 +0,0 @@
import config from "../../config.js";
import { meApi } from "types/types.js";
export default async function unFollowBack() {
const profile: meApi = await
(await fetch(`https://${config.uwuzu.host}/api/me/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
})
})).json();
for (let i = 0; i < profile.followee.length; i++) {
const followUser = profile.followee[i];
if (
profile.follower.indexOf(followUser) === -1
) {
setTimeout(async () => {
const req = await fetch(`https://${config.uwuzu.host}/api/users/unfollow/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
userId: followUser,
}),
});
const res = await req.text();
console.log(`フォロー解除: ${res}`)
}, 100);
}
}
}

View File

@ -4,7 +4,7 @@ import type * as types from "types/types.js";
import config from "../config.js"; import config from "../config.js";
export default async function weatherNotice() { export async function weatherNotice() {
console.log("----------------"); console.log("----------------");
// 仮投稿 // 仮投稿
@ -26,7 +26,10 @@ export default async function weatherNotice() {
console.log(`天気仮投稿:${JSON.stringify(ueuseData)}`); console.log(`天気仮投稿:${JSON.stringify(ueuseData)}`);
weatherReply(ueuseData.uniqid);
}
export async function weatherReply(uniqid: string) {
// インデックス // インデックス
const splitCount = config.weather.splitCount; const splitCount = config.weather.splitCount;
const total = cityList.length; const total = cityList.length;
@ -109,13 +112,13 @@ export default async function weatherNotice() {
body: JSON.stringify({ body: JSON.stringify({
token: config.uwuzu.apiToken, token: config.uwuzu.apiToken,
text: weatherResults[i], text: weatherResults[i],
replyid: ueuseData.uniqid replyid: uniqid,
}), }),
}, },
); );
const replyData: types.ueuseCreateApi = await resReply.json(); const replyData: types.ueuseCreateApi = await resReply.json();
console.log(`天気投稿${JSON.stringify(replyData)}`); console.log(`天気返信${JSON.stringify(replyData)}`);
} }
} }

22
types/types.d.ts vendored
View File

@ -23,6 +23,28 @@ export interface meApi {
language: String; language: String;
} }
export interface ueuse {
uniqid: string;
text: string;
account: {
username: string;
userid: string;
user_icon: string;
user_header: string;
};
photo1: Base64URLString;
photo2: Base64URLString;
photo3: Base64URLString;
photo4: Base64URLString;
video1: Base64URLString;
favorite: Array<string>;
favorite_cnt: string;
datetime: string;
abi: string;
abidatetime: string;
nsfw: boolean;
}
export interface ueuseCreateApi { export interface ueuseCreateApi {
uniqid: string; uniqid: string;
userid: string; userid: string;