Fix: distに震度分布画像のアセットと地域マップがコピーされるように / Del: 正確にスケジュールが動作する機能 / Fix: 返信とメンションの返答が記録されない問題 / Fix: 震度分布画像が投稿されない問題 / Chg: 震度分布画像のメッセージを変更 / Fix: 条件に合わなくても震度分布画像を生成する問題 / Fix: 震度分布画像に隙間が空く問題
This commit is contained in:
@@ -9,55 +9,42 @@ import unfollowCommand from "@/feature/command/unfollow";
|
||||
import miqCommand from "@/feature/command/miq";
|
||||
import initI18n from "@/lib/i18n";
|
||||
import config from "@/lib/config";
|
||||
import CronExpressionParser from "cron-parser";
|
||||
|
||||
await initI18n();
|
||||
|
||||
const next = BigInt(CronExpressionParser.parse(`*/${config.command.interval} * * * *`).next().getTime() * 1_000_000);
|
||||
while (process.hrtime.bigint() > next) {}
|
||||
|
||||
console.log("コマンドの処理を行います");
|
||||
|
||||
try {
|
||||
let ueuses: ueuseModule[] = [];
|
||||
|
||||
const mem = Memory.memory;
|
||||
let newLastReadReply = mem.lastReadReply;
|
||||
let newLastReadMention = mem.lastReadMention;
|
||||
|
||||
{
|
||||
const response = await client.request("me/notification/", {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
});
|
||||
const response = await client.request("me/notification/", { page: 1, limit: 20 });
|
||||
|
||||
if (response.success) {
|
||||
const notifications = response.data.filter(notification => notification.category === "reply" && typeof notification.valueid === "string");
|
||||
|
||||
const mem = Memory.memory;
|
||||
const lastReadReply = mem.lastReadReply;
|
||||
const notifications = response.data.filter(n => n.category === "reply" && typeof n.valueid === "string");
|
||||
|
||||
for (const [index, notification] of notifications.entries()) {
|
||||
if (notification.category !== "reply" || typeof notification.valueid !== "string")
|
||||
continue;
|
||||
|
||||
const ueuseResponse = await client.request("ueuse/get", {
|
||||
uniqid: notification.valueid,
|
||||
});
|
||||
const ueuseResponse = await client.request("ueuse/get", { uniqid: notification.valueid });
|
||||
|
||||
if (!ueuseResponse.success || !ueuseResponse.data[0]) {
|
||||
console.warn("返信通知からユーズを参照できないため、スキップします");
|
||||
continue;
|
||||
}
|
||||
|
||||
const time = new Date(ueuseResponse.data[0].datetime).getTime();
|
||||
const ueuseData = ueuseResponse.data[0];
|
||||
const time = new Date(ueuseData.datetime).getTime();
|
||||
|
||||
if (index === 0) {
|
||||
const mem = Memory.memory;
|
||||
mem.lastReadReply = time;
|
||||
Memory.memory = mem;
|
||||
}
|
||||
|
||||
if (lastReadReply >= time)
|
||||
if (mem.lastReadReply >= time)
|
||||
break;
|
||||
|
||||
ueuses.push(ueuseResponse.data[0]);
|
||||
if (index === 0)
|
||||
newLastReadReply = time;
|
||||
|
||||
ueuses.push(ueuseData);
|
||||
}
|
||||
} else {
|
||||
console.warn("返信通知の取得に失敗しましたが、続行します");
|
||||
@@ -73,21 +60,15 @@ try {
|
||||
if (response.success) {
|
||||
const mentions = response.data;
|
||||
|
||||
const mem = Memory.memory;
|
||||
const lastReadMention = mem.lastReadMention;
|
||||
|
||||
for (const [index, mention] of mentions.entries()) {
|
||||
const time = new Date(mention.datetime).getTime();
|
||||
|
||||
if (index === 0) {
|
||||
const mem = Memory.memory;
|
||||
mem.lastReadMention = time;
|
||||
Memory.memory = mem;
|
||||
}
|
||||
|
||||
if (lastReadMention >= time)
|
||||
if (mem.lastReadMention >= time)
|
||||
break;
|
||||
|
||||
if (index === 0)
|
||||
newLastReadMention = time;
|
||||
|
||||
ueuses.push(mention);
|
||||
}
|
||||
} else {
|
||||
@@ -95,7 +76,16 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
ueuses = [...new Set(ueuses)];
|
||||
mem.lastReadReply = newLastReadReply;
|
||||
mem.lastReadMention = newLastReadMention;
|
||||
Memory.memory = mem;
|
||||
|
||||
const seenIds = new Set();
|
||||
ueuses = ueuses.filter(ueuse => {
|
||||
if (seenIds.has(ueuse.uniqid)) return false;
|
||||
seenIds.add(ueuse.uniqid);
|
||||
return true;
|
||||
});
|
||||
|
||||
for (let i = 0; i < ueuses.length; i += config.command.maxParallels) {
|
||||
const chunk = ueuses.slice(i, i + config.command.maxParallels);
|
||||
|
||||
@@ -154,7 +154,9 @@ function getEdge<T extends any[]>(arr: T, property: keyof T[number]) {
|
||||
export default async function generateImage(message: any) {
|
||||
if (
|
||||
message.earthquake.hypocenter === undefined ||
|
||||
message.points === undefined
|
||||
message.earthquake.hypocenter?.name === "" ||
|
||||
!(Array.isArray(message.points)) ||
|
||||
message.points.length === 0
|
||||
)
|
||||
return "input_lack";
|
||||
|
||||
@@ -289,34 +291,12 @@ export default async function generateImage(message: any) {
|
||||
|
||||
xSize = tileXCount.most - tileXCount.least + 1;
|
||||
ySize = tileYCount.most - tileYCount.least + 1;
|
||||
|
||||
if (xSize > ySize) {
|
||||
tileSize = Math.round(WIDTH / xSize);
|
||||
} else {
|
||||
tileSize = Math.round(HEIGHT / ySize);
|
||||
}
|
||||
|
||||
// 全画面
|
||||
if (WIDTH - xSize * tileSize > 10) {
|
||||
const requireTilesX = Math.ceil(WIDTH / tileSize);
|
||||
const halfTilesX = Math.ceil(requireTilesX / 2);
|
||||
|
||||
tileXCount = {
|
||||
least: tileXCount.least - halfTilesX,
|
||||
most: tileXCount.most + halfTilesX,
|
||||
}
|
||||
}
|
||||
|
||||
if (HEIGHT - ySize * tileSize > 10) {
|
||||
const requireTilesY = Math.ceil(HEIGHT / tileSize);
|
||||
const halfTilesY = Math.ceil(requireTilesY / 2);
|
||||
|
||||
tileYCount = {
|
||||
least: tileYCount.least - halfTilesY,
|
||||
most: tileYCount.most + halfTilesY,
|
||||
}
|
||||
}
|
||||
|
||||
// 震源を中心とする
|
||||
const epicenterPosition = positions.filter(position => position.type === "epicenter")[0];
|
||||
if (!epicenterPosition)
|
||||
@@ -362,13 +342,37 @@ export default async function generateImage(message: any) {
|
||||
// タイルサイズ再計算
|
||||
xSize = tileXCount.most - tileXCount.least + 1;
|
||||
ySize = tileYCount.most - tileYCount.least + 1;
|
||||
|
||||
if (xSize > ySize) {
|
||||
tileSize = Math.round(WIDTH / xSize);
|
||||
} else {
|
||||
tileSize = Math.round(HEIGHT / ySize);
|
||||
}
|
||||
|
||||
// 全画面
|
||||
if (WIDTH - xSize * tileSize > 5) {
|
||||
const requireTilesX = Math.ceil(WIDTH / tileSize);
|
||||
const halfTilesX = Math.ceil(requireTilesX / 2);
|
||||
|
||||
tileXCount = {
|
||||
least: tileXCount.least - halfTilesX,
|
||||
most: tileXCount.most + halfTilesX,
|
||||
}
|
||||
}
|
||||
|
||||
if (HEIGHT - ySize * tileSize > 5) {
|
||||
const requireTilesY = Math.ceil(HEIGHT / tileSize);
|
||||
const halfTilesY = Math.ceil(requireTilesY / 2);
|
||||
|
||||
tileYCount = {
|
||||
least: tileYCount.least - halfTilesY,
|
||||
most: tileYCount.most + halfTilesY,
|
||||
}
|
||||
}
|
||||
|
||||
// タイル幅再計算
|
||||
xSize = tileXCount.most - tileXCount.least + 1;
|
||||
ySize = tileYCount.most - tileYCount.least + 1;
|
||||
|
||||
// 欠けているタイルを取得
|
||||
for (let xIndex = 0; xIndex < xSize; xIndex++) {
|
||||
const itX = xIndex + tileXCount.least;
|
||||
|
||||
@@ -169,61 +169,56 @@ const processMessage = async (message: any) => {
|
||||
.join(EOL.repeat(2))
|
||||
.trim();
|
||||
|
||||
let earthquakeUniqid: string | null = null;
|
||||
const earthquakeUeuses = await createUeuse({
|
||||
text: i18next.t("earthquakeNotice", {
|
||||
type: typeMessage[message.issue.type] ?? "地震情報",
|
||||
occuredTime: format(new Date(message.earthquake.time), "yyyy年M月d日 H:mm"),
|
||||
maxScale: scaleMessages[String(message.earthquake.maxScale)],
|
||||
epicenter: message.earthquake.hypocenter.name === ""
|
||||
? "不明"
|
||||
: message.earthquake.hypocenter.name,
|
||||
magnitude: message.earthquake.hypocenter.magnitude === -1
|
||||
? "不明"
|
||||
: `M${message.earthquake.hypocenter.magnitude.toFixed(1)}`,
|
||||
depth: message.earthquake.hypocenter.depth === 0
|
||||
? "ごく浅い"
|
||||
: (message.earthquake.hypocenter.depth === -1
|
||||
? "不明"
|
||||
: `${message.earthquake.hypocenter.depth}km`),
|
||||
domesticTsunami: domesticTsunamiMessages[(message.earthquake.domesticTsunami ?? "Unknown")],
|
||||
foreignTsunami: foreignTsunamiMessages[(message.earthquake.foreignTsunami ?? "Unknown")],
|
||||
points: pointsMsg === ""
|
||||
? ""
|
||||
: EOL.repeat(2) + pointsMsg,
|
||||
source: message.issue.source ?? "不明",
|
||||
comment: message.comments.freeFormComment === ""
|
||||
? ""
|
||||
: EOL + message.comments.freeFormComment + EOL,
|
||||
}),
|
||||
}, "地震発生情報");
|
||||
|
||||
await Promise.allSettled([
|
||||
(async () => {
|
||||
const ueuses = await createUeuse({
|
||||
text: i18next.t("earthquakeNotice", {
|
||||
type: typeMessage[message.issue.type] ?? "地震情報",
|
||||
occuredTime: format(new Date(message.earthquake.time), "yyyy年M月d日 H:mm"),
|
||||
maxScale: scaleMessages[String(message.earthquake.maxScale)],
|
||||
epicenter: message.earthquake.hypocenter.name === ""
|
||||
? "不明"
|
||||
: message.earthquake.hypocenter.name,
|
||||
magnitude: message.earthquake.hypocenter.magnitude === -1
|
||||
? "不明"
|
||||
: `M${message.earthquake.hypocenter.magnitude.toFixed(1)}`,
|
||||
depth: message.earthquake.hypocenter.depth === 0
|
||||
? "ごく浅い"
|
||||
: (message.earthquake.hypocenter.depth === -1
|
||||
? "不明"
|
||||
: `${message.earthquake.hypocenter.depth}km`),
|
||||
domesticTsunami: domesticTsunamiMessages[(message.earthquake.domesticTsunami ?? "Unknown")],
|
||||
foreignTsunami: foreignTsunamiMessages[(message.earthquake.foreignTsunami ?? "Unknown")],
|
||||
points: pointsMsg === ""
|
||||
? ""
|
||||
: EOL.repeat(2) + pointsMsg,
|
||||
source: message.issue.source ?? "不明",
|
||||
comment: message.comments.freeFormComment === ""
|
||||
? ""
|
||||
: EOL + message.comments.freeFormComment + EOL,
|
||||
}),
|
||||
}, "地震発生情報");
|
||||
|
||||
earthquakeUniqid = ueuses[0]?.uniqid ?? null;
|
||||
})(),
|
||||
(async () => {
|
||||
const result = await generateImage(message);
|
||||
|
||||
if (typeof result === "string") {
|
||||
console.warn("情報が不足しているため、地震の画像生成ができませんでした");
|
||||
return;
|
||||
}
|
||||
|
||||
while (typeof (earthquakeUniqid as string | null) !== "string") {}
|
||||
try {
|
||||
const image = await generateImage(message);
|
||||
|
||||
if (typeof image === "string") {
|
||||
throw "情報が不足しているため、地震の画像生成ができませんでした";
|
||||
} else {
|
||||
await createUeuse({
|
||||
text: "この地震の震度分布画像を生成しました。",
|
||||
text: i18next.t("earthquakeImageGenerated", {
|
||||
url: earthquakeUeuses[0]?.uniqid
|
||||
? `${config.uwuzu.origin}/!${earthquakeUeuses[0].uniqid}`
|
||||
: "不明",
|
||||
}),
|
||||
media: {
|
||||
photo: [
|
||||
result.toString("base64"),
|
||||
]
|
||||
image.toString("base64"),
|
||||
],
|
||||
},
|
||||
reuseid: (earthquakeUniqid as unknown as string),
|
||||
}, "震度分布画像");
|
||||
})(),
|
||||
]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 552:
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { createUeuse } from "@/lib/client";
|
||||
import initI18n from "@/lib/i18n";
|
||||
import CronExpressionParser from "cron-parser";
|
||||
import { format } from "date-fns";
|
||||
import i18next from "i18next";
|
||||
|
||||
await initI18n();
|
||||
|
||||
const next = BigInt(CronExpressionParser.parse("0 0 1 1 *").next().getTime() * 1_000_000);
|
||||
while (process.hrtime.bigint() > next) {}
|
||||
|
||||
console.log("新年迎春の投稿を行います");
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { createUeuse } from "@/lib/client";
|
||||
import initI18n from "@/lib/i18n";
|
||||
import CronExpressionParser from "cron-parser";
|
||||
import { format } from "date-fns";
|
||||
import i18next from "i18next";
|
||||
|
||||
await initI18n();
|
||||
|
||||
const next = BigInt(CronExpressionParser.parse("0 * * * *").next().getTime() * 1_000_000);
|
||||
while (process.hrtime.bigint() > next) {}
|
||||
|
||||
console.log("時報の投稿を行います");
|
||||
|
||||
try {
|
||||
|
||||
@@ -2,7 +2,6 @@ import client from "@/lib/client";
|
||||
import config from "@/lib/config";
|
||||
import initI18n from "@/lib/i18n";
|
||||
import Memory from "@/lib/memory";
|
||||
import CronExpressionParser from "cron-parser";
|
||||
import i18next from "i18next";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { EOL } from "node:os";
|
||||
@@ -65,12 +64,6 @@ if (
|
||||
) {
|
||||
await initI18n();
|
||||
|
||||
const cronStr = workerData.endsWith("Tomorrow")
|
||||
? "0 18 * * *"
|
||||
: "0 7 * * *"
|
||||
const next = BigInt(CronExpressionParser.parse(cronStr).next().getTime() * 1_000_000);
|
||||
while (process.hrtime.bigint() > next) {}
|
||||
|
||||
console.log("天気予報の投稿を行います");
|
||||
|
||||
try {
|
||||
|
||||
+13
-13
@@ -31,34 +31,34 @@ try {
|
||||
}
|
||||
|
||||
try {
|
||||
schedule("56 59 * * * *", async () => {
|
||||
schedule("0 * * * *", async () => {
|
||||
new Worker(`${import.meta.dirname}/feature/timeNotice.js`);
|
||||
});
|
||||
|
||||
schedule("56 59 6 * * *", async () => {
|
||||
schedule("0 7 * * *", async () => {
|
||||
new Worker(`${import.meta.dirname}/feature/weatherNotice.js`, {
|
||||
workerData: "scheduledWeatherNotice",
|
||||
});
|
||||
});
|
||||
|
||||
schedule("56 59 17 * * *", async () => {
|
||||
schedule("0 18 * * *", async () => {
|
||||
new Worker(`${import.meta.dirname}/feature/weatherNotice.js`, {
|
||||
workerData: "scheduledWeatherNoticeTomorrow",
|
||||
});
|
||||
});
|
||||
|
||||
const interval = config.command.interval;
|
||||
const targetMinutes = [];
|
||||
for (let i = interval - 1; i < 60; i += interval) {
|
||||
targetMinutes.push(i);
|
||||
}
|
||||
const minutesStr = targetMinutes.join(",");
|
||||
schedule(`56 ${minutesStr} * * * *`, async () => {
|
||||
schedule(`*/${config.command.interval} * * * *`, async () => {
|
||||
new Worker(`${import.meta.dirname}/feature/command/index.js`);
|
||||
});
|
||||
|
||||
schedule("56 59 23 31 12 *", () => {
|
||||
new Worker(`${import.meta.dirname}/feature/hnyNotice.js`);
|
||||
|
||||
let hnyWorker: Worker | undefined = undefined;
|
||||
|
||||
schedule("57 59 23 31 12 *", () => {
|
||||
hnyWorker = new Worker(`${import.meta.dirname}/feature/hnyNotice.js`);
|
||||
});
|
||||
|
||||
schedule("0 0 0 1 1 *", () => {
|
||||
hnyWorker?.postMessage("");
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error("message" in err
|
||||
|
||||
Reference in New Issue
Block a user