Compare commits

...

3 Commits
v8.0.2 ... main

Author SHA1 Message Date
Last2014 db719b8312 v8.1.2 2025-08-08 21:34:30 +09:00
Last2014 2966eee889 v8.1.1 2025-08-08 21:31:43 +09:00
Last2014 db5e174dd4 v8.1 2025-08-08 21:29:19 +09:00
29 changed files with 239 additions and 208 deletions

View File

@ -3,7 +3,7 @@ import config from "../config.js";
export default async function APICheck() {
try {
const req = await fetch(`https://${config.uwuzu.host}/api/me/`, {
const req = await fetch(`${config.uwuzu.host}/api/me/`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,

12
checks/legal.ts Normal file
View File

@ -0,0 +1,12 @@
import config from "../config.js";
import { styleText } from "util";
export default function LegalCheck() {
if (
config.legal.terms.length <= 50 ||
config.legal.terms.length <= 50
) {
console.log(styleText("red", "利用規約とプライバシーポリシーは50文字以上にしてください。"));
process.exit();
}
}

View File

@ -3,11 +3,16 @@ import PackagesCheck from "./packages.js";
import ConfigCheck from "./config.js";
import APICheck from "./api.js";
import VersionCheck from "./version.js";
import LegalCheck from "./legal.js";
import config from "../config.js";
export default async function Check() {
PackagesIsExist();
PackagesCheck();
ConfigCheck();
if (config.debug === undefined) {
LegalCheck()
}
await APICheck();
await VersionCheck();
}

View File

@ -26,7 +26,7 @@ export default async function VersionCheck() {
const releaseUrl = `${packageJson.repository.url}/releases/tag/${packageJson.tag}`;
await fetch(`https://${config.uwuzu.host}/api/ueuse/create`, {
await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,

View File

@ -35,6 +35,11 @@ const config: configTypes = {
to: "admin@noticeuwuzu.example.com", // 緊急時メール送信先(配列可)
},
},
// /report設定
report: {
isEnabled: true, // 有効/無効
message: "", // 報告者へのメッセージ
},
// 規約等
legal: {
terms: `
@ -51,16 +56,10 @@ const config: configTypes = {
port: 74919, // 配信ポート
},
},
// /report設定
report: {
isEnabled: true, // 有効/無効
message: "", // 報告者へのメッセージ
},
// uwuzuサーバー設定
uwuzu: {
apiToken: "TOKEN_EXAMPLE", // APIトークン
clientToken: "TOKEN_EXAMPLE", // クライアントトークン(任意)
host: "uwuzu.example.com", // サーバーホスト(HTTPSである必要があります)
host: "https://uwuzu.example.com", // サーバーホスト
},
};

19
main.ts
View File

@ -11,16 +11,14 @@ 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 EventDays from "./scripts/eventday.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();
@ -31,23 +29,34 @@ cron.schedule("0 * * * *", () => {
});
// コマンド(10分/1回)
cron.schedule('*/10 * * * *', () => {
cron.schedule("*/10 * * * *", () => {
Commands();
});
// 祝日などお知らせ(毎日0:00)
cron.schedule("0 0 * * *", () => {
EventDays();
});
// 天気お知らせ(毎日7:00)
import { setTimeout } from "timers";
cron.schedule("0 7 * * *", () => {
setTimeout(() => {
weatherNotice();
birthdayNotice();
}, 100);
});
// 管理パネル
import AdminPanel from "./panel/main.js";
import { styleText } from "util";
(async () => {
await AdminPanel();
})();
// 起動表示
console.log("BOTサーバーが起動しました");
import config from "./config.js";
if (config.debug !== undefined) {
console.log(styleText(["bgRed", "cyan", "bold"], "デバッグモードで起動中"));
}

View File

@ -1,7 +1,7 @@
{
"name": "notice-uwuzu",
"version": "v8.0.2@uwuzu1.6.1",
"tag": "v8.0.2",
"version": "v8.1.2@uwuzu1.6.1",
"tag": "v8.1.2",
"description": "Notice Bot for uwuzu",
"main": "dist/main.js",
"scripts": {
@ -49,6 +49,7 @@
"fs": "^0.0.1-security",
"node-cron": "^4.1.1",
"nodemailer": "^7.0.4",
"timers": "^0.1.1",
"typescript": "^5.9.2",
"ws": "^8.18.3"
},

View File

@ -9,6 +9,7 @@ import ueusePost from "./route/ueuse.js";
import WeatherUeuse from "./route/weather.js";
import API from "./route/api.js";
import Token from "./route/token.js";
import Debug from "./route/debug.js";
export default async function AdminPanel() {
// 無効
@ -26,6 +27,7 @@ export default async function AdminPanel() {
app.use(WeatherUeuse);
app.use(API);
app.use(Token);
app.use(Debug);
app.use(express.static("panel/public"));
app.listen(port, () => {

View File

@ -23,6 +23,10 @@
天気お知らせ
</button>
<button id="eventdayUeuse" class="border rounded-[10px] p-[5px] m-[10px] mt-[20px] cursor-pointer">
祝日等お知らせ
</button>
<button id="ueuse" class="border rounded-[10px] p-[5px] m-[10px] mt-[20px] cursor-pointer">
ユーズ投稿
</button>

View File

@ -26,6 +26,20 @@ document.getElementById("weatherUeuse").addEventListener("click", async () => {
}
});
document.getElementById("eventdayUeuse").addEventListener("click", async () => {
const req = await fetch("/actions/eventday", {
method: "POST",
});
const res = await req.text();
if (res === "Accepted") {
alert("祝日等お知らせを受け付けました");
} else {
alert(`祝日等お知らせの要求にエラーが発生しました:${res}`);
}
});
document.getElementById("ueuse").addEventListener("click", async () => {
const text = prompt("ユーズ内容").toLowerCase();

View File

@ -11,7 +11,7 @@ API.post("/actions/api", async (req, res, next) => {
const body = req.body.body;
try {
const apiReq = await fetch(`https://${config.uwuzu.host}/api${endpoint}`, {
const apiReq = await fetch(`${config.uwuzu.host}/api${endpoint}`, {
method: "POST",
body: JSON.stringify(body),
});

24
panel/route/debug.ts Normal file
View File

@ -0,0 +1,24 @@
import express from "express";
const Debug = express.Router();
import config from "../../config.js";
Debug.post("/actions/debug", (req, res, next) => {
res.status(501)
.send("GET Only");
});
Debug.get("/actions/debug", (req, res) => {
let debug;
if (config.debug === undefined) {
debug = false;
} else {
debug = true;
}
res.status(200)
.send(debug);
});
export default Debug;

25
panel/route/eventday.ts Normal file
View File

@ -0,0 +1,25 @@
import express from "express";
const EventdayUeuse = express.Router();
import EventDays from "../../scripts/eventday.js";
EventdayUeuse.post("/actions/eventday", (req, res) => {
try {
(async () => {
await EventDays();
})();
res.status(202)
.send("Accepted");
} catch(err) {
res.status(500)
.send(`Error: ${err}`);
}
});
EventdayUeuse.get("/actions/eventday", (req, res) => {
res.status(501)
.send("POST Only");
});
export default EventdayUeuse;

View File

@ -3,9 +3,6 @@ const Token = express.Router();
import config from "../../config.js";
Token.use(express.json());
Token.use(express.urlencoded({ extended: true }));
Token.post("/actions/token", (req, res, next) => {
res.status(501)
.send("GET Only");

View File

@ -11,18 +11,22 @@ ueusePost.post("/actions/ueuse", async (req, res, next) => {
const nsfw = req.body.nsfw;
try {
const ueuseReq = await fetch(`https://${config.uwuzu.host}/api/ueuse/create`, {
const ueuseReq = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
text: text,
text: `
${text}
noticeUwuzuの管理パネルから投稿されました
`,
nsfw: nsfw,
}),
});
const ueuseRes = await ueuseReq.json();
console.log(`ユーズ(管理パネル)${ueuseRes}`);
console.log(`ユーズ(管理パネル)${JSON.stringify(ueuseRes)}`);
res.status(200)
.send("Success");

View File

@ -1,14 +0,0 @@
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",
);
}
}

View File

@ -1,56 +0,0 @@
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

@ -1,88 +0,0 @@
import { ueuse } from "types/types";
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

@ -3,7 +3,7 @@ import config from "../../config.js";
import { Reply } from "./main.js";
export default async function Follow(data: ueuse) {
const followReq = await fetch(`https://${config.uwuzu.host}/api/users/follow`, {
const followReq = await fetch(`${config.uwuzu.host}/api/users/follow`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,

View File

@ -9,7 +9,6 @@ const helpsMin = {
"unfollow": "コマンド送信者をフォロー解除します。",
"weather": "天気を返信します。",
"report": "運営者に不具合などを報告します。",
"birthday": "誕生日を設定・削除できます。",
"legal terms": "利用規約を返信します。",
"legal privacy": "プライバシーポリシーを返信します。",
} as { [key: string]: string };
@ -41,12 +40,6 @@ const helpsFull = {
使
\`/report\`を使用してそのユーズの追記に内容を入力することで使用できます。
`,
"birthday": `
設定された誕生日の7:00に祝われます
yyyy/MM/ddの形式で誕生日を入力することで誕生日を設定できます
\`delete\`と入力することで誕生日のデータを削除できます。
`,
"legal terms": `
`,

View File

@ -11,7 +11,6 @@ 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";
@ -38,7 +37,7 @@ function cutAfterChar(str: string, char: string) {
}
export async function Reply(text: string, reply: string) {
const req = await fetch(`https://${config.uwuzu.host}/api/ueuse/create`, {
const req = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
@ -65,7 +64,7 @@ function alreadyAdd(data: string) {
export default async function Commands() {
const mentionsReq = await fetch(
`https://${config.uwuzu.host}/api/ueuse/mentions`, {
`${config.uwuzu.host}/api/ueuse/mentions`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
@ -84,6 +83,10 @@ export default async function Commands() {
const data = mentions[key];
// 除外ユーズ
if (data.text === undefined) {
break;
}
if (alreadyCommands.indexOf(data.uniqid) !== -1) {
break;
}
@ -130,9 +133,6 @@ export default async function Commands() {
case "weather":
Weather(data);
break;
case "birthday":
Birthday(data);
break;
default:
const reply = await Reply(`

View File

@ -48,7 +48,7 @@ export default async function Report(data: ueuse) {
BOT管理者さんnoticeUwuzu自動送信メールです
@${data.account.userid}@${config.uwuzu.host}/reportコマンドを利用した報告がありました
https://${config.uwuzu.host}/!${data.uniqid}
${config.uwuzu.host}/!${data.uniqid}
${data.abi}
`,

View File

@ -3,7 +3,7 @@ import config from "../../config.js";
import { Reply } from "./main.js";
export default async function UnFollow(data: ueuse) {
const unfollowReq = await fetch(`https://${config.uwuzu.host}/api/users/unfollow`, {
const unfollowReq = await fetch(`${config.uwuzu.host}/api/users/unfollow`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,

View File

@ -485,7 +485,7 @@ async function event(earthquakeInfo: any): Promise<void> {
}
async function ueuse(text: string) {
const res = await fetch(`https://${config.uwuzu.host}/api/ueuse/create`, {
const res = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,

30
scripts/eventday.ts Normal file
View File

@ -0,0 +1,30 @@
import { format } from "date-fns";
import eventdays from "./eventdayData.js";
import config from "../config.js";
export default async function EventDays() {
const now = format(new Date(), "MM/dd");
for (let i = 0; i < Object.keys(eventdays).length; i++) {
const day = Object.keys(eventdays)[i];
const value = Object.values(eventdays)[i];
const name = value.name;
const message = value.message;
if (day === now) {
const req = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
method: "POST",
body: JSON.stringify({
token: config.uwuzu.apiToken,
text:
`今日は${name}です
${message}`,
}),
});
const res = await req.json();
console.log("祝日等ユーズ:", res);
}
}
}

70
scripts/eventdayData.ts Normal file
View File

@ -0,0 +1,70 @@
interface eventdaysValue {
name: string;
message: string;
}
const eventdays = {
"01/01": {
name: "元日",
message: "はい年越した瞬間地球にいなかった~",
},
"02/11": {
name: "建国記念日",
message: "建国記念日とかいう強制休暇",
},
"04/29": {
name: "昭和の日",
message: "平成の日は???",
},
"05/03": {
name: "憲法記念日",
message: "憲法決めた日とか祝日じゃなくていいだろ",
},
"05/04": {
name: "みどりの日",
message:
`なんだよみどりの日って
`,
},
"05/05": {
name: "こどもの日",
message: "こどもの日あるならおとなの日もあっていいだろ",
},
"07/07": {
name: "七夕",
message:
`祭りでも行っとけ
Last2014は家でサーバーいじってるから`,
},
"08/11": {
name: "山の日",
message:
`空の日と山の日も作れよ
3`,
},
"11/03": {
name: "文化の日",
message: "ネットミームできるたびに休みになればいいのになぁ...",
},
"11/23": {
name: "勤労感謝の日",
message: "学生は神!!",
},
"12/24": {
name: "クリスマスイブ",
message:
`リア充爆破します
by `,
},
"12/25": {
name: "クリスマス",
message: `リア充爆破します(2回目)
by `,
},
"12/31": {
name: "大晦日",
message: "大掃除!!大掃除!!",
},
} as { [key: string]: eventdaysValue };
export default eventdays;

View File

@ -28,7 +28,7 @@ export default async function timeNotice() {
} else {
// 投稿
const resUeuse = await fetch(
`https://${config.uwuzu.host}/api/ueuse/create`,
`${config.uwuzu.host}/api/ueuse/create`,
{
method: "POST",
body: JSON.stringify({

View File

@ -9,7 +9,7 @@ export async function weatherNotice() {
// 仮投稿
const resUeuse = await fetch(
`https://${config.uwuzu.host}/api/ueuse/create`,
`${config.uwuzu.host}/api/ueuse/create`,
{
method: "POST",
body: JSON.stringify({
@ -107,7 +107,7 @@ export async function weatherReply(uniqid: string) {
// 分割投稿
for (let i = 0; i < splitCount; i++) {
const resReply = await fetch(
`https://${config.uwuzu.host}/api/ueuse/create`,
`${config.uwuzu.host}/api/ueuse/create`,
{
method: "POST",
body: JSON.stringify({

14
types/config.d.ts vendored
View File

@ -42,6 +42,11 @@ interface emergencyMinTypes {
isEnabled: false;
}
interface reportTypes {
isEnabled: boolean;
message: string;
}
interface legalTypes {
terms: string;
privacy: string;
@ -62,14 +67,8 @@ interface adminTypes {
panel: PanelFullTypes | PanelMinTypes;
}
interface reportTypes {
isEnabled: boolean;
message: string;
}
interface uwuzuTypes {
apiToken: string;
clientToken?: string;
host: string;
}
@ -79,8 +78,9 @@ export interface configTypes {
weather: weatherTypes;
emergency: emergencyFullTypes | emergencyMinTypes;
report: reportTypes;
legal: legalTypes;
admin: adminTypes;
report: reportTypes;
uwuzu: uwuzuTypes;
debug?: true;
}