v25.8.5@uwuzu1.6.4
This commit is contained in:
parent
db719b8312
commit
bbf2d66b57
|
|
@ -19,6 +19,7 @@ Automatic notification bot for uwuzu
|
|||
- Follow back
|
||||
- Unfollow
|
||||
- Weather Repost
|
||||
- Make it a quote
|
||||
- Startup requirements check
|
||||
- Check package existence
|
||||
- Required package version check
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ const config: configTypes = {
|
|||
weather: {
|
||||
splitCount: 4, // 返信の分割数
|
||||
},
|
||||
// Make it a quote設定
|
||||
miq: true, // 有効/無効
|
||||
|
||||
// 緊急時設定
|
||||
emergency: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'
|
||||
|
||||
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.
|
|
@ -0,0 +1,134 @@
|
|||
import { createCanvas, loadImage, registerFont } from "canvas";
|
||||
import { writeFileSync } from "fs";
|
||||
import sharp from "sharp";
|
||||
import { MiQOptions } from "./miq";
|
||||
|
||||
function textReplace(
|
||||
text: string
|
||||
) {
|
||||
let result = "";
|
||||
|
||||
// 改行削除
|
||||
text = text.replaceAll("\n", "");
|
||||
|
||||
// 10文字/1回で改行を追加
|
||||
let maxLength = 10;
|
||||
if (text.length > maxLength) {
|
||||
for (let i = 0; i < text.length; i += maxLength) {
|
||||
result += text.substring(i, i + maxLength) + "\n";
|
||||
}
|
||||
result = result.trimEnd();
|
||||
}
|
||||
|
||||
// 80文字以上は「...」で省略
|
||||
maxLength = 80;
|
||||
if (result.length > maxLength) {
|
||||
result = result.substring(0, maxLength)
|
||||
+ "...";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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) {
|
||||
// フォント読み込み
|
||||
registerFont("miq/fonts/NotoSansJP.ttf", { family: "Noto Sans JP" });
|
||||
|
||||
// 初期化
|
||||
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 Noto Sans JP";
|
||||
ctx.fillStyle = "white";
|
||||
ctx.textAlign = "left";
|
||||
ctx.textBaseline = "middle";
|
||||
let x = 670;
|
||||
let y = 480;
|
||||
ctx.fillText("-", x, y);
|
||||
ctx.fillText(userName, x+40, y, canvas.width-(x+40));
|
||||
|
||||
// ユーザーID描画
|
||||
ctx.font = "28px Noto Sans JP";
|
||||
ctx.fillStyle = "#3c3c3c";
|
||||
ctx.fillText(`@${userID}`, x+120, y+50, canvas.width-(x+120));
|
||||
|
||||
// 本文描画
|
||||
ctx.font = "48px Noto Sans JP";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = "white";
|
||||
text = textReplace(text);
|
||||
x = 870;
|
||||
y = 30;
|
||||
ctx.fillText(text, x, y+50);
|
||||
|
||||
// フェード描画
|
||||
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);
|
||||
|
||||
// 返答
|
||||
if (type === "Buffer") {
|
||||
return canvas.toBuffer();
|
||||
} else if (type === "Base64") {
|
||||
return canvas.toDataURL();
|
||||
} else {
|
||||
return "Error: The type property is invalid.";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
type MiQType =
|
||||
"Buffer" |
|
||||
"Base64"
|
||||
|
||||
export interface MiQOptions {
|
||||
type: MiQType;
|
||||
color: boolean;
|
||||
text: string;
|
||||
iconURL: string;
|
||||
userName: string;
|
||||
userID: string;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "notice-uwuzu",
|
||||
"version": "v8.1.2@uwuzu1.6.1",
|
||||
"tag": "v8.1.2",
|
||||
"version": "v25.8.5@uwuzu1.6.4",
|
||||
"tag": "v25.8.5",
|
||||
"description": "Notice Bot for uwuzu",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
|
|
@ -42,13 +42,16 @@
|
|||
"@types/node": "^24.0.7",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"@types/nodemailer": "^6.4.17",
|
||||
"@types/sharp": "^0.31.1",
|
||||
"@types/ws": "^8.18.1",
|
||||
"canvas": "^3.2.0",
|
||||
"child_process": "^1.0.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"express": "^5.1.0",
|
||||
"fs": "^0.0.1-security",
|
||||
"node-cron": "^4.1.1",
|
||||
"nodemailer": "^7.0.4",
|
||||
"sharp": "^0.34.3",
|
||||
"timers": "^0.1.1",
|
||||
"typescript": "^5.9.2",
|
||||
"ws": "^8.18.3"
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@ const initialFile: Array<string> = [];
|
|||
|
||||
// コマンド読み込み
|
||||
import Info from "./info.js";
|
||||
import Help from "./help.js";
|
||||
import Follow from "./follow.js";
|
||||
import UnFollow from "./unfollow.js";
|
||||
import Weather from "./weather.js";
|
||||
import Help from "./help.js";
|
||||
import MakeItAQuote from "./miq.js";
|
||||
import Report from "./report.js";
|
||||
import Terms from "./legal/terms.js"
|
||||
import PrivacyPolicy from "./legal/privacy.js";
|
||||
|
|
@ -36,6 +37,43 @@ function cutAfterChar(str: string, char: string) {
|
|||
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) {
|
||||
const req = await fetch(`${config.uwuzu.host}/api/ueuse/create`, {
|
||||
method: "POST",
|
||||
|
|
@ -99,16 +137,19 @@ export default async function Commands() {
|
|||
break;
|
||||
}
|
||||
|
||||
if (data.text.indexOf("/") === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// コマンド処理
|
||||
console.log("--------");
|
||||
|
||||
const commandName = cutAfterChar(data.text, "/");
|
||||
const commandName = await commandSearch(data.text);
|
||||
console.log(commandName);
|
||||
|
||||
alreadyAdd(data.uniqid);
|
||||
|
||||
switch (commandName) {
|
||||
case "":
|
||||
break;
|
||||
case "info":
|
||||
Info(data);
|
||||
break;
|
||||
|
|
@ -133,6 +174,9 @@ export default async function Commands() {
|
|||
case "weather":
|
||||
Weather(data);
|
||||
break;
|
||||
case "miq":
|
||||
MakeItAQuote(data);
|
||||
break;
|
||||
default:
|
||||
const reply = await Reply(`
|
||||
不明なコマンドです。
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
import { ueuse } from "../../types/types";
|
||||
import MiQ from "../../miq/main.js";
|
||||
import config from "../../config.js";
|
||||
|
||||
export default async function MakeItAQuote(data: ueuse) {
|
||||
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 img = await MiQ({
|
||||
type: "Base64",
|
||||
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,
|
||||
replyid: data.uniqid,
|
||||
}),
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
const res = await req.json();
|
||||
|
||||
console.log("MiQ:", res);
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ export interface configTypes {
|
|||
time: timeTypes,
|
||||
earthquake: earthquakeTypes;
|
||||
weather: weatherTypes;
|
||||
miq: boolean;
|
||||
|
||||
emergency: emergencyFullTypes | emergencyMinTypes;
|
||||
report: reportTypes;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export interface meApi {
|
|||
|
||||
export interface ueuse {
|
||||
uniqid: string;
|
||||
relpyid: string;
|
||||
replyid: string;
|
||||
reuseid: string;
|
||||
text: string;
|
||||
account: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue