Files
noticeUwuzu/src/feature/weatherNotice.ts
T

198 lines
5.2 KiB
TypeScript

import client from "@/lib/client";
import config from "@/lib/config";
import Memory from "@/lib/memory";
import { readFileSync } from "node:fs";
import { EOL } from "node:os";
import { isMainThread, workerData } from "node:worker_threads";
const cityList = [
"016010",
"020010",
"030010",
"040010",
"050010",
"060010",
"070010",
"080010",
"090010",
"100010",
"110010",
"120010",
"130010",
"140010",
"150010",
"160010",
"170010",
"180010",
"190010",
"200010",
"210010",
"220010",
"230010",
"240010",
"250010",
"260010",
"270000",
"280010",
"290010",
"300010",
"310010",
"320010",
"330010",
"340010",
"350010",
"360010",
"370000",
"380010",
"390010",
"400010",
"410010",
"420010",
"430010",
"440010",
"450010",
"460010",
"471010",
];
if (
!isMainThread &&
typeof workerData === "string" &&
workerData.startsWith("scheduledWeatherNotice")
) {
console.log("天気予報の投稿を行います");
try {
let provisionalUeuse;
let success = false;
for (let attempt = 1; attempt <= config.ueuse.maxRetries; attempt++) {
const provisionalText = [];
provisionalText.push(`${workerData.endsWith("Tomorrow")
? "明日"
: "今日"}の天気`);
provisionalText.push("※タイムラインが埋まるため返信に記載しています。");
provisionalUeuse = await client.request("ueuse/create", {
text: provisionalText.join(EOL),
});
if (provisionalUeuse.success) {
success = true;
break;
}
console.warn(`天気仮投稿に失敗しました (試行 ${attempt}/${config.ueuse.maxRetries}):`, provisionalUeuse.error_code);
if (attempt < config.ueuse.maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
if (!success || !provisionalUeuse?.success) {
console.error("天気仮投稿の全試行に失敗したため、終了します。");
process.exit(1);
}
console.log("天気仮投稿:", provisionalUeuse.uniqid);
await weatherReply(provisionalUeuse.uniqid, workerData.endsWith("Tomorrow"));
process.exit(0);
} catch (err: any) {
console.error("message" in err
? err.message
: err);
process.exit(1);
}
}
export async function weatherReply(uniqid: string, isTomorrow: boolean) {
// インデックス
const aboutFullLength = 3100;
const mem = Memory.memory;
const splitCount = Math.round(aboutFullLength / mem.max_length);
const total = cityList.length;
const chunkSizes = Array(splitCount).fill(0).map((_, i) =>
Math.floor((total + i) / splitCount)
);
// 分割インデックス
let start = 0;
const ranges: [number, number][] = chunkSizes.map(size => {
const range: [number, number] = [start, start + size];
start += size;
return range;
});
// 配列作成
const weatherResults = Array(splitCount).fill("");
// package.json取得
const packageJson = JSON.parse(readFileSync(`${import.meta.dirname}/../../package.json`, "utf-8"));
// 天気取得
for (let chunkIndex = 0; chunkIndex < splitCount; chunkIndex++) {
const range = ranges[chunkIndex];
if (!range) continue;
const [chunkStart, chunkEnd] = range;
for (let i = chunkStart; i < chunkEnd; i++) {
const res = await fetch(`https://weather.tsukumijima.net/api/forecast/city/${cityList[i]}`, {
headers: {
"User-Agent": `noticeUwuzu/${packageJson.version}`,
},
});
const data = await res.json();
const itDay = isTomorrow
? data.forecasts[1]
: data.forecasts[0];
// 天気
const areaText = [];
areaText.push(`${data.location.city}`);
areaText.push(`⛅天気: ${itDay.telop ?? "取得できませんでした"}`);
areaText.push(`🔆最高気温: ${itDay.temperature.max.celsius
? `${itDay.temperature.max.celsius}`
: "取得できませんでした"}`);
areaText.push(`🔅最低気温: ${itDay.temperature.min.celsius
? `${itDay.temperature.min.celsius}`
: "取得できませんでした"}`);
areaText.push(`☔降水確率: ${
itDay.chanceOfRain.T06_12 !== null &&
itDay.chanceOfRain.T06_12 !== "--%"
? itDay.chanceOfRain.T06_12
: "取得できませんでした"}`);
weatherResults[chunkIndex] += areaText.join(EOL) + EOL.repeat(2);
}
}
// 分割投稿
for (let i = 0; i < splitCount; i++) {
let replyUeuse;
let success = false;
for (let attempt = 1; attempt <= config.ueuse.maxRetries; attempt++) {
replyUeuse = await client.request("ueuse/create", {
text: weatherResults[i].trim(),
replyid: uniqid,
});
if (replyUeuse.success) {
success = true;
break;
}
console.warn(`天気返信に失敗しました (試行 ${attempt}/${config.ueuse.maxRetries}):`, replyUeuse.error_code);
if (attempt < config.ueuse.maxRetries) {
await new Promise(resolve => setTimeout(resolve, config.ueuse.retryInterval));
}
}
if (!success || !replyUeuse?.success) {
console.error("天気返信の全試行に失敗したため、終了します。");
process.exit(1);
}
console.log("天気返信:", replyUeuse.uniqid);
}
}