Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9a4fe8763 | |||
| ed3606778e | |||
| fb3e233244 | |||
| ca96f83a44 | |||
| 97af8da4dd | |||
| a83054f5ce | |||
| bbf2d66b57 |
@@ -19,6 +19,7 @@ Automatic notification bot for uwuzu
|
|||||||
- Follow back
|
- Follow back
|
||||||
- Unfollow
|
- Unfollow
|
||||||
- Weather Repost
|
- Weather Repost
|
||||||
|
- Make it a quote
|
||||||
- Startup requirements check
|
- Startup requirements check
|
||||||
- Check package existence
|
- Check package existence
|
||||||
- Required package version check
|
- Required package version check
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ const config: configTypes = {
|
|||||||
weather: {
|
weather: {
|
||||||
splitCount: 4, // 返信の分割数
|
splitCount: 4, // 返信の分割数
|
||||||
},
|
},
|
||||||
|
// Make it a quote設定
|
||||||
|
miq: true, // 有効/無効
|
||||||
|
|
||||||
// 緊急時設定
|
// 緊急時設定
|
||||||
emergency: {
|
emergency: {
|
||||||
|
|||||||
@@ -58,5 +58,6 @@ console.log("BOTサーバーが起動しました");
|
|||||||
|
|
||||||
import config from "./config.js";
|
import config from "./config.js";
|
||||||
if (config.debug !== undefined) {
|
if (config.debug !== undefined) {
|
||||||
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
console.log(styleText(["bgRed", "cyan", "bold"], "デバッグモードで起動中"));
|
console.log(styleText(["bgRed", "cyan", "bold"], "デバッグモードで起動中"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
Binary file not shown.
+174
@@ -0,0 +1,174 @@
|
|||||||
|
import { createCanvas, loadImage, registerFont } from "canvas";
|
||||||
|
import sharp from "sharp";
|
||||||
|
import { MiQOptions } from "./miq";
|
||||||
|
|
||||||
|
// フォント読み込み
|
||||||
|
registerFont("miq/fonts/MPLUS.ttf", {
|
||||||
|
family: "M PLUS Rounded 1c",
|
||||||
|
weight: "400",
|
||||||
|
});
|
||||||
|
|
||||||
|
function maxLengthCut(
|
||||||
|
text: string,
|
||||||
|
maxLength: number,
|
||||||
|
) {
|
||||||
|
if (text.length > maxLength) {
|
||||||
|
text = text.substring(0, maxLength)
|
||||||
|
+ "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoLineBreak(
|
||||||
|
text: string,
|
||||||
|
maxWidth: number,
|
||||||
|
font: string = '48px "M PLUS Rounded 1c"'
|
||||||
|
): string {
|
||||||
|
const ctx = createCanvas(maxWidth, 100).getContext("2d");
|
||||||
|
ctx.font = font;
|
||||||
|
|
||||||
|
const lines: string[] = [];
|
||||||
|
let currentLine = "";
|
||||||
|
|
||||||
|
for (let i = 0; i < text.length; i++) {
|
||||||
|
const char = text[i];
|
||||||
|
const testLine = currentLine + char;
|
||||||
|
const width = ctx.measureText(testLine).width;
|
||||||
|
|
||||||
|
if (width > maxWidth) {
|
||||||
|
lines.push(currentLine);
|
||||||
|
currentLine = char;
|
||||||
|
|
||||||
|
while (ctx.measureText(currentLine).width > maxWidth && currentLine.length > 1) {
|
||||||
|
const cutPoint = currentLine.length - 1;
|
||||||
|
lines.push(currentLine.slice(0, cutPoint));
|
||||||
|
currentLine = currentLine.slice(cutPoint);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentLine = testLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLine) lines.push(currentLine);
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
function textReplace(
|
||||||
|
text: string,
|
||||||
|
maxWidth: number,
|
||||||
|
font?: string
|
||||||
|
) {
|
||||||
|
// 改行削除
|
||||||
|
text = text.replaceAll("\n", "");
|
||||||
|
text = text.replaceAll("\r", "");
|
||||||
|
// 自動改行
|
||||||
|
text = autoLineBreak(text, maxWidth, font);
|
||||||
|
// 100文字以上を省略
|
||||||
|
text = maxLengthCut(text, 100);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function iconReplace(
|
||||||
|
color: boolean,
|
||||||
|
iconURL: string
|
||||||
|
) {
|
||||||
|
let result = "";
|
||||||
|
|
||||||
|
const buffer = await(await fetch(iconURL, {
|
||||||
|
method: "GET",
|
||||||
|
cache: "no-store",
|
||||||
|
})).arrayBuffer();
|
||||||
|
|
||||||
|
if (color) {
|
||||||
|
const img = await sharp(Buffer.from(buffer))
|
||||||
|
.png()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
result = `data:image/png;base64,${img.toString("base64")}`;
|
||||||
|
} else {
|
||||||
|
const img = await sharp(Buffer.from(buffer))
|
||||||
|
.png()
|
||||||
|
.grayscale()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
result = `data:image/png;base64,${img.toString("base64")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function to generate
|
||||||
|
* Make it a quote on Node.js.
|
||||||
|
*/
|
||||||
|
export default async function MiQ({
|
||||||
|
type,
|
||||||
|
color,
|
||||||
|
text,
|
||||||
|
iconURL,
|
||||||
|
userName,
|
||||||
|
userID,
|
||||||
|
}: MiQOptions) {
|
||||||
|
// 初期化
|
||||||
|
const canvas = createCanvas(1200, 630);
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// 背景描画
|
||||||
|
ctx.fillStyle = "black";
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
// アイコン描画
|
||||||
|
const iconImg = await loadImage(await iconReplace(
|
||||||
|
color,
|
||||||
|
iconURL,
|
||||||
|
));
|
||||||
|
const iconSize = canvas.height;
|
||||||
|
ctx.drawImage(iconImg, 0, 0, iconSize, iconSize);
|
||||||
|
|
||||||
|
// ユーザー名描画
|
||||||
|
ctx.font = '38px "M PLUS Rounded 1c"';
|
||||||
|
ctx.fillStyle = "white";
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
ctx.textBaseline = "middle";
|
||||||
|
let x = 910;
|
||||||
|
let y = 480;
|
||||||
|
ctx.fillText(`- ${userName}`, x, y, canvas.width-iconSize);
|
||||||
|
|
||||||
|
// ユーザーID描画
|
||||||
|
ctx.font = '28px "M PLUS Rounded 1c"';
|
||||||
|
ctx.fillStyle = "#b4b4b4";
|
||||||
|
ctx.fillText(`@${userID}`, x, y+50, canvas.width-iconSize);
|
||||||
|
|
||||||
|
// 本文描画
|
||||||
|
const maxWidth = canvas.width - iconSize;
|
||||||
|
ctx.font = '48px "M PLUS Rounded 1c"';
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
ctx.textBaseline = "middle";
|
||||||
|
ctx.fillStyle = "white";
|
||||||
|
text = textReplace(text, maxWidth, ctx.font);
|
||||||
|
ctx.fillText(text, x, 80);
|
||||||
|
|
||||||
|
// フェード描画
|
||||||
|
const fadeColor = "black";
|
||||||
|
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
|
||||||
|
gradient.addColorStop(0, "rgba(0, 0, 0, 0)");
|
||||||
|
gradient.addColorStop(0.5, fadeColor);
|
||||||
|
ctx.fillStyle = gradient;
|
||||||
|
ctx.fillRect(0, 0, iconSize, canvas.height);
|
||||||
|
|
||||||
|
// 返答
|
||||||
|
switch (type) {
|
||||||
|
case "Buffer":
|
||||||
|
return canvas.toBuffer();
|
||||||
|
case "Base64Data":
|
||||||
|
return canvas.toDataURL()
|
||||||
|
.replace("data:image/png;base64,", "");
|
||||||
|
case "Base64URL":
|
||||||
|
return canvas.toDataURL();
|
||||||
|
default:
|
||||||
|
return "Error: The type property is invalid.";
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
type MiQType =
|
||||||
|
"Buffer" |
|
||||||
|
"Base64Data" |
|
||||||
|
"Base64URL";
|
||||||
|
|
||||||
|
export interface MiQOptions {
|
||||||
|
type: MiQType;
|
||||||
|
color: boolean;
|
||||||
|
text: string;
|
||||||
|
iconURL: string;
|
||||||
|
userName: string;
|
||||||
|
userID: string;
|
||||||
|
}
|
||||||
+5
-2
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "notice-uwuzu",
|
"name": "notice-uwuzu",
|
||||||
"version": "v8.1.2@uwuzu1.6.1",
|
"version": "v25.8.9@uwuzu1.6.4",
|
||||||
"tag": "v8.1.2",
|
"tag": "v25.8.9",
|
||||||
"description": "Notice Bot for uwuzu",
|
"description": "Notice Bot for uwuzu",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -42,13 +42,16 @@
|
|||||||
"@types/node": "^24.0.7",
|
"@types/node": "^24.0.7",
|
||||||
"@types/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
|
"@types/sharp": "^0.31.1",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
|
"canvas": "^3.2.0",
|
||||||
"child_process": "^1.0.2",
|
"child_process": "^1.0.2",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"node-cron": "^4.1.1",
|
"node-cron": "^4.1.1",
|
||||||
"nodemailer": "^7.0.4",
|
"nodemailer": "^7.0.4",
|
||||||
|
"sharp": "^0.34.3",
|
||||||
"timers": "^0.1.1",
|
"timers": "^0.1.1",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.2",
|
||||||
"ws": "^8.18.3"
|
"ws": "^8.18.3"
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { meApi, ueuse } from "../../types/types";
|
||||||
|
import config from "../../config.js";
|
||||||
|
import { Reply } from "./main.js";
|
||||||
|
|
||||||
|
export default async function Delete(data: ueuse) {
|
||||||
|
const me: meApi = await (await fetch(`${config.uwuzu.host}/api/me/`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
}),
|
||||||
|
})).json()
|
||||||
|
|
||||||
|
const replyUeuse: ueuse = (await (await fetch(`${config.uwuzu.host}/api/ueuse/get`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
uniqid: data.replyid,
|
||||||
|
}),
|
||||||
|
})).json())["0"];
|
||||||
|
|
||||||
|
if (me.userid === replyUeuse.account.userid) {
|
||||||
|
const ueuseDelete = await (await fetch(`${config.uwuzu.host}/api/ueuse/delete`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
uniqid: data.replyid,
|
||||||
|
}),
|
||||||
|
})).json();
|
||||||
|
|
||||||
|
console.log("削除:", ueuseDelete);
|
||||||
|
|
||||||
|
if (ueuseDelete.success === true) {
|
||||||
|
console.log("削除通知:", await Reply(`
|
||||||
|
対象のユーズを削除しました。
|
||||||
|
`, data.uniqid));
|
||||||
|
} else {
|
||||||
|
console.log("削除失敗通知:", await Reply(`
|
||||||
|
対象のユーズを削除できませんでした。
|
||||||
|
`, data.uniqid));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.log("削除失敗通知(他人):", await Reply(`
|
||||||
|
削除するユーズが${me.username}のものではありません。
|
||||||
|
そのため削除できませんでした。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,10 @@ const helpsMin = {
|
|||||||
"follow": "コマンド送信者をフォローします。",
|
"follow": "コマンド送信者をフォローします。",
|
||||||
"unfollow": "コマンド送信者をフォロー解除します。",
|
"unfollow": "コマンド送信者をフォロー解除します。",
|
||||||
"weather": "天気を返信します。",
|
"weather": "天気を返信します。",
|
||||||
|
"miq": "Make it a Quoteを生成します。",
|
||||||
|
"miq permission": "あなたに対してのMake it a Quoteを生成する要求者を制限できます。",
|
||||||
|
"miq allow": "Make it a Quoteの許可制にて生成を許可します。",
|
||||||
|
"delete": "ユーズを削除します。",
|
||||||
"report": "運営者に不具合などを報告します。",
|
"report": "運営者に不具合などを報告します。",
|
||||||
"legal terms": "利用規約を返信します。",
|
"legal terms": "利用規約を返信します。",
|
||||||
"legal privacy": "プライバシーポリシーを返信します。",
|
"legal privacy": "プライバシーポリシーを返信します。",
|
||||||
@@ -35,6 +39,26 @@ const helpsFull = {
|
|||||||
毎日7:00の天気を再投稿するわけではなく、
|
毎日7:00の天気を再投稿するわけではなく、
|
||||||
再取得して返信します。
|
再取得して返信します。
|
||||||
`,
|
`,
|
||||||
|
"miq": `
|
||||||
|
Make it a Quoteを生成します。
|
||||||
|
追記に\`color: true\`と入力することでカラーモードに変更可能です。
|
||||||
|
\`/delete\`コマンドを使用して削除できます。
|
||||||
|
`,
|
||||||
|
"miq permission": `
|
||||||
|
あなたに対してのMake it a Quoteを生成する要求者を制限できます。
|
||||||
|
確認するには追記なしで実行してください。
|
||||||
|
変更するには以下のいずれかを追記に入力して実行してください。
|
||||||
|
- \`me\`: 自分自身のみになります。あなたのみが生成でき、あなた以外が生成を要求すると拒否されます。
|
||||||
|
- \`everyone\`: 全体公開になります。全てのユーザーが許可なしにあなたのユーズでMake it a Quoteを生成できます。
|
||||||
|
- \`consent\`: 許可制になります。生成を要求されるとあなたにメンションが届き許可するかを選択できます。
|
||||||
|
`,
|
||||||
|
"miq allow": `
|
||||||
|
Make it a Quoteの許可制にて生成を許可します。
|
||||||
|
形式が異なる場合生成されません。
|
||||||
|
`,
|
||||||
|
"delete": `
|
||||||
|
BOTのユーズにて返信で使用すると返信先のユーズを削除します。
|
||||||
|
`,
|
||||||
"report": `
|
"report": `
|
||||||
不具合などを運営者にメールで報告できます。
|
不具合などを運営者にメールで報告できます。
|
||||||
運営者によって有効化されていないと使用できません。
|
運営者によって有効化されていないと使用できません。
|
||||||
@@ -68,6 +92,14 @@ export default async function Help(data: ueuse) {
|
|||||||
`, data.uniqid);
|
`, data.uniqid);
|
||||||
|
|
||||||
console.log("ヘルプ:", ueuse);
|
console.log("ヘルプ:", ueuse);
|
||||||
|
} else {
|
||||||
|
if (Object.keys(helpsFull).indexOf(data.abi) === -1) {
|
||||||
|
const ueuse = await Reply(`
|
||||||
|
不明なコマンドです。
|
||||||
|
機能を見る:${packageJson.repository.url}/wiki
|
||||||
|
`, data.uniqid);
|
||||||
|
|
||||||
|
console.log("ヘルプ(不明コマンド):", ueuse);
|
||||||
} else {
|
} else {
|
||||||
const ueuse = await Reply(`
|
const ueuse = await Reply(`
|
||||||
${helpsFull[data.abi]}
|
${helpsFull[data.abi]}
|
||||||
@@ -76,4 +108,5 @@ export default async function Help(data: ueuse) {
|
|||||||
|
|
||||||
console.log("ヘルプ:", ueuse);
|
console.log("ヘルプ:", ueuse);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,17 @@ const initialFile: Array<string> = [];
|
|||||||
|
|
||||||
// コマンド読み込み
|
// コマンド読み込み
|
||||||
import Info from "./info.js";
|
import Info from "./info.js";
|
||||||
|
import Help from "./help.js";
|
||||||
import Follow from "./follow.js";
|
import Follow from "./follow.js";
|
||||||
import UnFollow from "./unfollow.js";
|
import UnFollow from "./unfollow.js";
|
||||||
import Weather from "./weather.js";
|
import Weather from "./weather.js";
|
||||||
import Help from "./help.js";
|
|
||||||
import Report from "./report.js";
|
import Report from "./report.js";
|
||||||
import Terms from "./legal/terms.js"
|
import Terms from "./legal/terms.js"
|
||||||
import PrivacyPolicy from "./legal/privacy.js";
|
import PrivacyPolicy from "./legal/privacy.js";
|
||||||
|
import Delete from "./delete.js";
|
||||||
|
import MakeItAQuote from "./miq/main.js";
|
||||||
|
import MiQPermission from "./miq/permission.js";
|
||||||
|
import MiQAllow from "./miq/allow.js";
|
||||||
|
|
||||||
// 初期化
|
// 初期化
|
||||||
if (!fs.existsSync("data/alreadyCommands.json")) {
|
if (!fs.existsSync("data/alreadyCommands.json")) {
|
||||||
@@ -36,6 +40,43 @@ function cutAfterChar(str: string, char: string) {
|
|||||||
return str.substring(index + 1);
|
return str.substring(index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function commandSearch(text: string) {
|
||||||
|
// /のある行を特定
|
||||||
|
const lines = text.split(/\n/);
|
||||||
|
let slashLine: number = -1;
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
if (lines[i].indexOf("/") !== -1) {
|
||||||
|
slashLine = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /がない場合は無を返答
|
||||||
|
if (slashLine === -1) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// BOTのユーザーIDを取得
|
||||||
|
const userid: string = (await (await fetch(`${config.uwuzu.host}/api/me/`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
}),
|
||||||
|
})).json()).userid;
|
||||||
|
|
||||||
|
// BOTへのメンションを削除
|
||||||
|
let slashLineText = lines[slashLine];
|
||||||
|
slashLineText = slashLineText.replace(`@${userid}`, "");
|
||||||
|
|
||||||
|
// /以降の文字を取得
|
||||||
|
slashLineText = cutAfterChar(slashLineText, "/");
|
||||||
|
|
||||||
|
// 前後の空白を削除
|
||||||
|
slashLineText = slashLineText.trimStart().trimEnd();
|
||||||
|
|
||||||
|
return slashLineText;
|
||||||
|
}
|
||||||
|
|
||||||
export async function Reply(text: string, reply: string) {
|
export async function Reply(text: string, reply: string) {
|
||||||
const req = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
|
const req = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -99,16 +140,18 @@ export default async function Commands() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.text.indexOf("/") === -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// コマンド処理
|
// コマンド処理
|
||||||
console.log("--------");
|
console.log("--------");
|
||||||
|
|
||||||
const commandName = cutAfterChar(data.text, "/");
|
const commandName = await commandSearch(data.text);
|
||||||
|
|
||||||
alreadyAdd(data.uniqid);
|
alreadyAdd(data.uniqid);
|
||||||
|
|
||||||
switch (commandName) {
|
switch (commandName) {
|
||||||
case "":
|
|
||||||
break;
|
|
||||||
case "info":
|
case "info":
|
||||||
Info(data);
|
Info(data);
|
||||||
break;
|
break;
|
||||||
@@ -133,6 +176,18 @@ export default async function Commands() {
|
|||||||
case "weather":
|
case "weather":
|
||||||
Weather(data);
|
Weather(data);
|
||||||
break;
|
break;
|
||||||
|
case "miq":
|
||||||
|
MakeItAQuote(data);
|
||||||
|
break;
|
||||||
|
case "miq permission":
|
||||||
|
MiQPermission(data);
|
||||||
|
break;
|
||||||
|
case "miq allow":
|
||||||
|
MiQAllow(data);
|
||||||
|
break;
|
||||||
|
case "delete":
|
||||||
|
Delete(data);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
const reply = await Reply(`
|
const reply = await Reply(`
|
||||||
不明なコマンドです。
|
不明なコマンドです。
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
import { meApi, ueuse } from "../../../types/types";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import config from "../../../config.js";
|
||||||
|
import { Reply } from "../main.js";
|
||||||
|
import { Permission } from "./permission";
|
||||||
|
import MiQ from "../../../miq/main.js";
|
||||||
|
|
||||||
|
export default async function MiQAllow(data: ueuse) {
|
||||||
|
if (!config.miq) {
|
||||||
|
console.log("MiQ(管理者無効):", await Reply(`
|
||||||
|
BOT管理者によってMake it a quoteが無効化されています。
|
||||||
|
そのため\`/miq\`はご利用いただけません。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.replyid === "") {
|
||||||
|
console.log("MiQ許可制(誤ユーズ):", await Reply(`
|
||||||
|
形式が正規ではありません。
|
||||||
|
`, data.uniqid));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 権限一覧取得
|
||||||
|
const permissions: { [user: string]: Permission } =
|
||||||
|
JSON.parse(readFileSync("data/miqPermissions.json", "utf-8"));
|
||||||
|
|
||||||
|
if (permissions[data.account.userid] !== "consent") {
|
||||||
|
console.log("MiQ許可制(許可制以外):", await Reply(`
|
||||||
|
あなたに対してのMake it a Quoteの生成要求者が許可制に設定されていません。
|
||||||
|
そのため、\`/miq allow\`はご利用いただけません。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmUeuse: ueuse = (await (
|
||||||
|
await fetch(`${config.uwuzu.host}/api/ueuse/get`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
uniqid: data.replyid,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
).json())["0"];
|
||||||
|
|
||||||
|
const me: meApi = await (
|
||||||
|
await fetch(`${config.uwuzu.host}/api/me/`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
).json()
|
||||||
|
|
||||||
|
if (confirmUeuse.account.userid !== me.userid) {
|
||||||
|
console.log("MiQ許可制(誤アカウント):", await Reply(`
|
||||||
|
返信先がこのBOTではありません。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (confirmUeuse.replyid === "") {
|
||||||
|
console.log("MiQ許可制(誤ユーズ):", await Reply(`
|
||||||
|
形式が正規ではありません。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestUeuse: ueuse = (await (
|
||||||
|
await fetch(`${config.uwuzu.host}/api/ueuse/get`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
uniqid: confirmUeuse.replyid,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
).json())["0"];
|
||||||
|
|
||||||
|
if (requestUeuse.replyid === "") {
|
||||||
|
console.log("MiQ許可制(誤ユーズ):", await Reply(`
|
||||||
|
形式が正規ではありません。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const miqUeuse: ueuse = (await (
|
||||||
|
await fetch(`${config.uwuzu.host}/api/ueuse/get`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
uniqid: requestUeuse.replyid,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
).json())["0"];
|
||||||
|
|
||||||
|
let color: boolean;
|
||||||
|
let msg: string;
|
||||||
|
if (requestUeuse.abi === "color: true") {
|
||||||
|
msg = "カラーモードでMake it a Quoteを生成しました。";
|
||||||
|
color = true;
|
||||||
|
} else if (requestUeuse.abi === "color: false") {
|
||||||
|
msg = "モノクロモードでMake it a Quoteを生成しました。";
|
||||||
|
color = false;
|
||||||
|
} else {
|
||||||
|
msg = "ご指定がないためモノクロモードでMake it a Quoteを生成しました。";
|
||||||
|
color = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const img = await MiQ({
|
||||||
|
type: "Base64Data",
|
||||||
|
color: color,
|
||||||
|
text: miqUeuse.text,
|
||||||
|
iconURL: miqUeuse.account.user_icon,
|
||||||
|
userName: miqUeuse.account.username,
|
||||||
|
userID: miqUeuse.account.userid,
|
||||||
|
});
|
||||||
|
|
||||||
|
const req = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
text: msg,
|
||||||
|
image1: img,
|
||||||
|
nsfw: miqUeuse.nsfw,
|
||||||
|
replyid: data.uniqid,
|
||||||
|
}),
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await req.json();
|
||||||
|
|
||||||
|
console.log("MiQ(許可制):", res);
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import { ueuse } from "../../../types/types";
|
||||||
|
import MiQ from "../../../miq/main.js";
|
||||||
|
import config from "../../../config.js";
|
||||||
|
import { Reply } from "../main.js";
|
||||||
|
import { readFileSync, writeFileSync } from "fs";
|
||||||
|
import { Permission } from "./permission";
|
||||||
|
|
||||||
|
export default async function MakeItAQuote(data: ueuse) {
|
||||||
|
if (!config.miq) {
|
||||||
|
console.log("MiQ(管理者無効):", await Reply(`
|
||||||
|
BOT管理者によってMake it a quoteが無効化されています。
|
||||||
|
そのため\`/miq\`はご利用いただけません。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let color: boolean;
|
||||||
|
let msg: string;
|
||||||
|
|
||||||
|
if (data.abi === "color: true") {
|
||||||
|
msg = "カラーモードでMake it a Quoteを生成しました。";
|
||||||
|
color = true;
|
||||||
|
} else if (data.abi === "color: false") {
|
||||||
|
msg = "モノクロモードでMake it a Quoteを生成しました。";
|
||||||
|
color = false;
|
||||||
|
} else {
|
||||||
|
msg = "ご指定がないためモノクロモードでMake it a Quoteを生成しました。";
|
||||||
|
color = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ueuseData: ueuse = (await (
|
||||||
|
await fetch(`${config.uwuzu.host}/api/ueuse/get`, {
|
||||||
|
method: "POST",
|
||||||
|
cache: "no-store",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
uniqid: data.replyid,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
).json())["0"];
|
||||||
|
|
||||||
|
console.log(ueuseData);
|
||||||
|
|
||||||
|
// 権限一覧取得
|
||||||
|
const permissions: { [user: string]: Permission } =
|
||||||
|
JSON.parse(readFileSync("data/miqPermissions.json", "utf-8"));
|
||||||
|
|
||||||
|
// 初期化
|
||||||
|
if (permissions[ueuseData.account.userid] === undefined) {
|
||||||
|
permissions[ueuseData.account.userid] = "consent";
|
||||||
|
writeFileSync(
|
||||||
|
"data/miqPermissions.json",
|
||||||
|
JSON.stringify(permissions),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
permissions[ueuseData.account.userid] === "me" &&
|
||||||
|
ueuseData.account.userid !== data.account.userid
|
||||||
|
) {
|
||||||
|
console.log("MiQ(自分自身専用):", await Reply(`
|
||||||
|
生成元ユーズの投稿者が生成要求者を自分自身のみに設定しています。
|
||||||
|
しかし、あなたは投稿者自身ではないためこのユーズにMake it a Quoteを使用することはできません。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permissions[ueuseData.account.userid] === "consent") {
|
||||||
|
console.log("MiQ(許可制):", await Reply(`
|
||||||
|
生成元ユーズの投稿者が生成要求者を許可制に設定しています。
|
||||||
|
このユーズにMake it a Quoteを使用するには、
|
||||||
|
@${ueuseData.account.userid}さんがこのユーズに返信で\`/miq allow\`を使用する必要があります。
|
||||||
|
`, data.uniqid));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const img = await MiQ({
|
||||||
|
type: "Base64Data",
|
||||||
|
color: color,
|
||||||
|
text: ueuseData.text,
|
||||||
|
iconURL: ueuseData.account.user_icon,
|
||||||
|
userName: ueuseData.account.username,
|
||||||
|
userID: ueuseData.account.userid,
|
||||||
|
});
|
||||||
|
|
||||||
|
const req = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: config.uwuzu.apiToken,
|
||||||
|
text: msg,
|
||||||
|
image1: img,
|
||||||
|
nsfw: data.nsfw,
|
||||||
|
replyid: data.uniqid,
|
||||||
|
}),
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await req.json();
|
||||||
|
|
||||||
|
console.log("MiQ:", res);
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import { ueuse } from "../../../types/types";
|
||||||
|
import { Reply } from "../main.js";
|
||||||
|
import config from "../../../config.js";
|
||||||
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
||||||
|
|
||||||
|
// 初期化
|
||||||
|
const initialFile = {};
|
||||||
|
if (!existsSync("data/miqPermissions.json")) {
|
||||||
|
writeFileSync(
|
||||||
|
"data/miqPermissions.json",
|
||||||
|
JSON.stringify(initialFile),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Permission =
|
||||||
|
"consent" |
|
||||||
|
"everyone" |
|
||||||
|
"me";
|
||||||
|
|
||||||
|
const PermissionsNames: { [name: string]: string } = {
|
||||||
|
"consent": "許可制",
|
||||||
|
"everyone": "全体公開",
|
||||||
|
"me": "自身のみ",
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function MiQPermission(data: ueuse) {
|
||||||
|
if (!config.miq) {
|
||||||
|
await Reply(`
|
||||||
|
BOT管理者によってMake it a quoteが無効化されています。
|
||||||
|
そのため\`/miq\`はご利用いただけません。
|
||||||
|
`, data.uniqid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissions: { [user: string]: string } =
|
||||||
|
JSON.parse(readFileSync("data/miqPermissions.json", "utf-8"));
|
||||||
|
|
||||||
|
// 初期化
|
||||||
|
if (permissions[data.account.userid] === undefined) {
|
||||||
|
permissions[data.account.userid] = "consent";
|
||||||
|
writeFileSync(
|
||||||
|
"data/miqPermissions.json",
|
||||||
|
JSON.stringify(permissions),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
data.abi === "" ||
|
||||||
|
data.abi === "none"
|
||||||
|
) {
|
||||||
|
await Reply(`
|
||||||
|
あなたに対してのMake it a Quoteを生成するための権限は「${PermissionsNames[permissions[data.account.userid]]}」です。
|
||||||
|
`, data.uniqid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestPermission = data.abi.trimEnd();
|
||||||
|
|
||||||
|
if (PermissionsNames[requestPermission] === undefined) {
|
||||||
|
await Reply(`
|
||||||
|
変更希望の権限「${requestPermission}」はご指定できません。
|
||||||
|
\`consent\`、\`everyone\`、\`me\`のいずれかからご選択ください。
|
||||||
|
`, data.uniqid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions[data.account.userid] = requestPermission;
|
||||||
|
writeFileSync(
|
||||||
|
"data/miqPermissions.json",
|
||||||
|
JSON.stringify(permissions),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
await Reply(`
|
||||||
|
あなたに対してのMake it a Quoteを生成するための権限を「${PermissionsNames[requestPermission]}」に変更しました。
|
||||||
|
`, data.uniqid);
|
||||||
|
}
|
||||||
Vendored
+1
@@ -76,6 +76,7 @@ export interface configTypes {
|
|||||||
time: timeTypes,
|
time: timeTypes,
|
||||||
earthquake: earthquakeTypes;
|
earthquake: earthquakeTypes;
|
||||||
weather: weatherTypes;
|
weather: weatherTypes;
|
||||||
|
miq: boolean;
|
||||||
|
|
||||||
emergency: emergencyFullTypes | emergencyMinTypes;
|
emergency: emergencyFullTypes | emergencyMinTypes;
|
||||||
report: reportTypes;
|
report: reportTypes;
|
||||||
|
|||||||
Vendored
+1
-1
@@ -25,7 +25,7 @@ export interface meApi {
|
|||||||
|
|
||||||
export interface ueuse {
|
export interface ueuse {
|
||||||
uniqid: string;
|
uniqid: string;
|
||||||
relpyid: string;
|
replyid: string;
|
||||||
reuseid: string;
|
reuseid: string;
|
||||||
text: string;
|
text: string;
|
||||||
account: {
|
account: {
|
||||||
|
|||||||
Reference in New Issue
Block a user