198 lines
5.2 KiB
TypeScript
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);
|
|
}
|
|
} |