diff --git a/.gitignore b/.gitignore index f360113..a767307 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ /memory.json /config/** !/config/example.yaml -/src/feature/earthquake/generateImage/data*.json diff --git a/locales/ja.yaml b/locales/ja.yaml index 7b29372..f985400 100644 --- a/locales/ja.yaml +++ b/locales/ja.yaml @@ -19,6 +19,9 @@ earthquakeNotice: | {{ foreignTsunami }}{{ points }} {{ comment }} 🔬情報源: P2P地震速報 - {{ source }} +earthquakeImageGenerated: | + 地震の震度分布画像を生成しました。 + 地震情報ユーズ: {{ url }} tsunamiAreaMsg: | 【{{ name }}】{{ immediate }} 🏷️種別: {{ grade }} diff --git a/package.json b/package.json index 45fa826..0c3cdbb 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/index.js", "scripts": { "start": "node .", - "build": "tsc && tsc-alias" + "build": "tsc && tsc-alias && cpy \"{**/*.json,**/*.png}\" ../dist --cwd=src && cpy \"260420.json\" dist" }, "author": { "name": "Last2014", @@ -17,7 +17,7 @@ "@types/node": "^25.5.2", "@types/ws": "^8.18.1", "better-uwuzu-sdk": "git+https://gitea.last2014.com/last2014/better-uwuzu-sdk.git#1.1.7", - "cron-parser": "^5.5.0", + "cpy-cli": "^7.0.0", "date-fns": "^4.1.0", "fs": "0.0.1-security", "i18next": "^26.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 903e42a..26af841 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,9 +17,9 @@ importers: better-uwuzu-sdk: specifier: git+https://gitea.last2014.com/last2014/better-uwuzu-sdk.git#1.1.7 version: git+https://gitea.last2014.com/last2014/better-uwuzu-sdk.git#8017146b1a2d6264d051b54afccdd46571b5fd00 - cron-parser: - specifier: ^5.5.0 - version: 5.5.0 + cpy-cli: + specifier: ^7.0.0 + version: 7.0.0 date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -232,6 +232,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + '@types/node@25.5.2': resolution: {integrity: sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==} @@ -301,10 +305,19 @@ packages: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} - cron-parser@5.5.0: - resolution: {integrity: sha512-oML4lKUXxizYswqmxuOCpgFS8BNUJpIu6k/2HVHyaL8Ynnf3wdf9tkns0yRdJLSIjkJ+b0DXHMZEHGpMwjnPww==} + copy-file@11.1.0: + resolution: {integrity: sha512-X8XDzyvYaA6msMyAM575CUoygY5b44QzLcGRKsK3MFmXcOvQa518dNPLsKYwkYsn72g3EiW+LE0ytd/FlqWmyw==} engines: {node: '>=18'} + cpy-cli@7.0.0: + resolution: {integrity: sha512-uGCdhIxGfZcPXidCuT8w1jBknVXFx0un7NLjzqBZcdnkIWtLUnWMPk5TC37ceoVjwASLSNsRtTXXNTuFIyE2ng==} + engines: {node: '>=20'} + hasBin: true + + cpy@13.2.2: + resolution: {integrity: sha512-FEc7gmNSj4mDQCWNt3mByVn3qZX3EjMvggiqgCQPF1yJAFfyX6Ai/emN89w18TRp+QcFmdTLgX3hfNnIVgYHcw==} + engines: {node: '>=20'} + date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} @@ -406,10 +419,17 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + globby@16.2.0: + resolution: {integrity: sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==} + engines: {node: '>=20'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -440,6 +460,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -474,6 +498,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -482,14 +510,18 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} - luxon@3.7.2: - resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} - engines: {node: '>=12'} + junk@4.0.1: + resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} + engines: {node: '>=12.20'} math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + meow@14.1.0: + resolution: {integrity: sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==} + engines: {node: '>=20'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -540,6 +572,22 @@ packages: os@0.1.2: resolution: {integrity: sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==} + p-event@6.0.1: + resolution: {integrity: sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==} + engines: {node: '>=16.17'} + + p-filter@4.1.0: + resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} + engines: {node: '>=18'} + + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + + p-timeout@6.1.4: + resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} + engines: {node: '>=14.16'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -624,6 +672,10 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -661,6 +713,10 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -811,6 +867,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@sindresorhus/merge-streams@4.0.0': {} + '@types/node@25.5.2': dependencies: undici-types: 7.18.2 @@ -893,9 +951,25 @@ snapshots: commander@9.5.0: {} - cron-parser@5.5.0: + copy-file@11.1.0: dependencies: - luxon: 3.7.2 + graceful-fs: 4.2.11 + p-event: 6.0.1 + + cpy-cli@7.0.0: + dependencies: + cpy: 13.2.2 + globby: 16.2.0 + meow: 14.1.0 + + cpy@13.2.2: + dependencies: + copy-file: 11.1.0 + globby: 16.2.0 + junk: 4.0.1 + micromatch: 4.0.8 + p-filter: 4.1.0 + p-map: 7.0.4 date-fns@4.1.0: {} @@ -1005,8 +1079,19 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + globby@16.2.0: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + is-path-inside: 4.0.0 + slash: 5.1.0 + unicorn-magic: 0.4.0 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 @@ -1031,6 +1116,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.5: {} + inherits@2.0.4: {} ini@1.3.8: {} @@ -1062,6 +1149,8 @@ snapshots: is-number@7.0.0: {} + is-path-inside@4.0.0: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -1073,10 +1162,12 @@ snapshots: dependencies: which-typed-array: 1.1.20 - luxon@3.7.2: {} + junk@4.0.1: {} math-intrinsics@1.1.0: {} + meow@14.1.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -1119,6 +1210,18 @@ snapshots: os@0.1.2: {} + p-event@6.0.1: + dependencies: + p-timeout: 6.1.4 + + p-filter@4.1.0: + dependencies: + p-map: 7.0.4 + + p-map@7.0.4: {} + + p-timeout@6.1.4: {} + path-type@4.0.0: {} picomatch@2.3.2: {} @@ -1238,6 +1341,8 @@ snapshots: slash@3.0.0: {} + slash@5.1.0: {} + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -1284,6 +1389,8 @@ snapshots: undici-types@7.18.2: {} + unicorn-magic@0.4.0: {} + util-deprecate@1.0.2: {} util@0.12.5: diff --git a/src/feature/command/index.ts b/src/feature/command/index.ts index e319177..c929732 100644 --- a/src/feature/command/index.ts +++ b/src/feature/command/index.ts @@ -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); diff --git a/src/feature/earthquake/generateImage/index.ts b/src/feature/earthquake/generateImage/index.ts index f065cc1..3d4e6c3 100644 --- a/src/feature/earthquake/generateImage/index.ts +++ b/src/feature/earthquake/generateImage/index.ts @@ -154,7 +154,9 @@ function getEdge(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; diff --git a/src/feature/earthquake/index.ts b/src/feature/earthquake/index.ts index 649b0ee..2074b8a 100644 --- a/src/feature/earthquake/index.ts +++ b/src/feature/earthquake/index.ts @@ -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: diff --git a/src/feature/hnyNotice.ts b/src/feature/hnyNotice.ts index 0d74eba..cba1df7 100644 --- a/src/feature/hnyNotice.ts +++ b/src/feature/hnyNotice.ts @@ -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 { diff --git a/src/feature/timeNotice.ts b/src/feature/timeNotice.ts index 1d76c9b..9a82b21 100644 --- a/src/feature/timeNotice.ts +++ b/src/feature/timeNotice.ts @@ -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 { diff --git a/src/feature/weatherNotice.ts b/src/feature/weatherNotice.ts index e9c18b3..8282583 100644 --- a/src/feature/weatherNotice.ts +++ b/src/feature/weatherNotice.ts @@ -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 { diff --git a/src/index.ts b/src/index.ts index a2d3bb0..4d0846d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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