1735
This commit is contained in:
1 parent
b86b170814
commit
192032d780
2 files changed
+46
-112
No files matched your search
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
import "./.next/types/routes.d.ts";
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
@@ -391,6 +391,17 @@ async function handleInlineCallback(chatId: number, queryId: string, data: strin
|
|||||||
try { await tg("answerCallbackQuery", { callback_query_id: queryId }); } catch (_e) {}
|
try { await tg("answerCallbackQuery", { callback_query_id: queryId }); } catch (_e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 新增:处理语音消息(增强版:保存文件 + 转文字 + 生成短代码)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
async function handleVoiceEnhanced(chatId: number, fileId: string, duration?: number) {
|
||||||
|
try {
|
||||||
|
const fs = await import("fs");
|
||||||
|
const path = await import("path");
|
||||||
|
const { getSession } = await import("./sessions");
|
||||||
|
const { transcribeAudio } = await import("@/lib/voice");
|
||||||
|
|
||||||
const s = getSession(chatId);
|
const s = getSession(chatId);
|
||||||
if (!s.dirPath) {
|
if (!s.dirPath) {
|
||||||
await sendMessage(chatId, "❌ 请先发 /new 或 /edit 开始写作");
|
await sendMessage(chatId, "❌ 请先发 /new 或 /edit 开始写作");
|
||||||
@@ -438,7 +449,11 @@ async function handleInlineCallback(chatId: number, queryId: string, data: strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleAudio(chatId: number, fileId: string, fileName?: string, mimeType?: string) {
|
// ============================================================
|
||||||
|
// 新增:处理音频文件(增强版:支持封面图)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
async function handleAudioEnhanced(chatId: number, fileId: string, fileName?: string) {
|
||||||
try {
|
try {
|
||||||
const fs = await import("fs");
|
const fs = await import("fs");
|
||||||
const path = await import("path");
|
const path = await import("path");
|
||||||
@@ -470,7 +485,7 @@ async function handleAudio(chatId: number, fileId: string, fileName?: string, mi
|
|||||||
fs.writeFileSync(path.join(articleDir, filename), Buffer.from(audioBuffer));
|
fs.writeFileSync(path.join(articleDir, filename), Buffer.from(audioBuffer));
|
||||||
|
|
||||||
const session = getSession(chatId);
|
const session = getSession(chatId);
|
||||||
session._pendingAudio = { filename, fileId };
|
session._pendingAudio = { filename, fileId, name: null, artist: null };
|
||||||
|
|
||||||
await tg("sendMessage", {
|
await tg("sendMessage", {
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
@@ -486,31 +501,8 @@ async function handleAudio(chatId: number, fileId: string, fileName?: string, mi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleAudioInfo(chatId: number, text: string): Promise<boolean> {
|
// ============================================================
|
||||||
try {
|
// 新增:处理图片(增强版:支持封面图上传 + 实况照片引导)
|
||||||
const { getSession } = await import("./sessions");
|
|
||||||
const s = getSession(chatId);
|
|
||||||
|
|
||||||
if (!s._pendingAudio) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { filename } = s._pendingAudio;
|
|
||||||
delete s._pendingAudio;
|
|
||||||
|
|
||||||
let name = "未知歌曲";
|
|
||||||
let artist = "未知艺术家";
|
|
||||||
|
|
||||||
const parts = text.split(/[-–—]/);
|
|
||||||
if (parts.length >= 2) {
|
|
||||||
name = parts[0].trim();
|
|
||||||
artist = parts.slice(1).join("-").trim();
|
|
||||||
} else if (text.trim()) {
|
|
||||||
name = text.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
co// ============================================================
|
|
||||||
// 增强版 handlePhoto:支持封面图上传 + 实况照片引导
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[], caption?: string) {
|
async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[], caption?: string) {
|
||||||
@@ -540,7 +532,6 @@ async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[]
|
|||||||
const fileUrl = "https://api.telegram.org/file/bot" + TG_TOKEN + "/" + filePath;
|
const fileUrl = "https://api.telegram.org/file/bot" + TG_TOKEN + "/" + filePath;
|
||||||
const imgBuffer = await fetch(fileUrl).then((r) => r.arrayBuffer());
|
const imgBuffer = await fetch(fileUrl).then((r) => r.arrayBuffer());
|
||||||
|
|
||||||
// 保存图片
|
|
||||||
const articleDir = s.dirPath;
|
const articleDir = s.dirPath;
|
||||||
if (!fs.existsSync(articleDir)) fs.mkdirSync(articleDir, { recursive: true });
|
if (!fs.existsSync(articleDir)) fs.mkdirSync(articleDir, { recursive: true });
|
||||||
|
|
||||||
@@ -551,7 +542,6 @@ async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[]
|
|||||||
const imgCaption = caption || "image";
|
const imgCaption = caption || "image";
|
||||||
appendContent(chatId, `\n\n`);
|
appendContent(chatId, `\n\n`);
|
||||||
|
|
||||||
// 实况照片引导提示
|
|
||||||
await sendMessage(chatId, `📷 图片已保存:${filename}
|
await sendMessage(chatId, `📷 图片已保存:${filename}
|
||||||
|
|
||||||
💡 <b>提示:</b>如果您发送的是 iOS 实况照片(Live Photo),
|
💡 <b>提示:</b>如果您发送的是 iOS 实况照片(Live Photo),
|
||||||
@@ -561,7 +551,6 @@ async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[]
|
|||||||
2. 或者单独发送视频部分
|
2. 或者单独发送视频部分
|
||||||
|
|
||||||
继续发送其他内容...</b>`, { parse_mode: "HTML" });
|
继续发送其他内容...</b>`, { parse_mode: "HTML" });
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[bot:photo]", e instanceof Error ? e.message : String(e));
|
console.error("[bot:photo]", e instanceof Error ? e.message : String(e));
|
||||||
await sendMessage(chatId, "❌ 图片保存失败");
|
await sendMessage(chatId, "❌ 图片保存失败");
|
||||||
@@ -569,7 +558,7 @@ async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// 处理音乐封面图
|
// 新增:处理音乐封面图
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
async function handleAudioCover(chatId: number, photos: { file_id: string }[]) {
|
async function handleAudioCover(chatId: number, photos: { file_id: string }[]) {
|
||||||
@@ -584,9 +573,8 @@ async function handleAudioCover(chatId: number, photos: { file_id: string }[]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { filename } = s._pendingAudio;
|
const { filename, name, artist } = s._pendingAudio;
|
||||||
|
|
||||||
// 获取最大的图片
|
|
||||||
const largestPhoto = photos[photos.length - 1];
|
const largestPhoto = photos[photos.length - 1];
|
||||||
const fileRes = await tg<{ file_path?: string }>("getFile", { file_id: largestPhoto.file_id });
|
const fileRes = await tg<{ file_path?: string }>("getFile", { file_id: largestPhoto.file_id });
|
||||||
if (!fileRes.ok || !fileRes.result?.file_path) {
|
if (!fileRes.ok || !fileRes.result?.file_path) {
|
||||||
@@ -598,25 +586,13 @@ async function handleAudioCover(chatId: number, photos: { file_id: string }[]) {
|
|||||||
const fileUrl = "https://api.telegram.org/file/bot" + TG_TOKEN + "/" + filePath;
|
const fileUrl = "https://api.telegram.org/file/bot" + TG_TOKEN + "/" + filePath;
|
||||||
const imgBuffer = await fetch(fileUrl).then((r) => r.arrayBuffer());
|
const imgBuffer = await fetch(fileUrl).then((r) => r.arrayBuffer());
|
||||||
|
|
||||||
// 保存封面图
|
|
||||||
const articleDir = s.dirPath;
|
const articleDir = s.dirPath;
|
||||||
const ext = filePath.split(".").pop() || "jpg";
|
const ext = filePath.split(".").pop() || "jpg";
|
||||||
const coverFilename = Date.now() + "-cover." + ext;
|
const coverFilename = Date.now() + "-cover." + ext;
|
||||||
fs.writeFileSync(path.join(articleDir, coverFilename), Buffer.from(imgBuffer));
|
fs.writeFileSync(path.join(articleDir, coverFilename), Buffer.from(imgBuffer));
|
||||||
|
|
||||||
// 更新音频信息
|
|
||||||
const audioInfo = s._pendingAudio;
|
|
||||||
delete s._pendingAudio;
|
delete s._pendingAudio;
|
||||||
|
|
||||||
// 生成带封面的音乐卡片
|
|
||||||
let name = "未知歌曲";
|
|
||||||
let artist = "未知艺术家";
|
|
||||||
|
|
||||||
if (audioInfo.name && audioInfo.artist) {
|
|
||||||
name = audioInfo.name;
|
|
||||||
artist = audioInfo.artist;
|
|
||||||
}
|
|
||||||
|
|
||||||
const musicCardShortcode = `\n\n{{< music-card src="${filename}" name="${name}" artist="${artist}" cover="${coverFilename}" >}}\n\n`;
|
const musicCardShortcode = `\n\n{{< music-card src="${filename}" name="${name}" artist="${artist}" cover="${coverFilename}" >}}\n\n`;
|
||||||
appendContent(chatId, musicCardShortcode);
|
appendContent(chatId, musicCardShortcode);
|
||||||
|
|
||||||
@@ -626,7 +602,6 @@ async function handleAudioCover(chatId: number, photos: { file_id: string }[]) {
|
|||||||
📌 歌曲:${name}
|
📌 歌曲:${name}
|
||||||
🎤 歌手:${artist}
|
🎤 歌手:${artist}
|
||||||
🖼️ 封面:${coverFilename}`, { parse_mode: "HTML" });
|
🖼️ 封面:${coverFilename}`, { parse_mode: "HTML" });
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[bot:audio-cover]", e instanceof Error ? e.message : String(e));
|
console.error("[bot:audio-cover]", e instanceof Error ? e.message : String(e));
|
||||||
await sendMessage(chatId, "❌ 封面图保存失败");
|
await sendMessage(chatId, "❌ 封面图保存失败");
|
||||||
@@ -634,66 +609,10 @@ async function handleAudioCover(chatId: number, photos: { file_id: string }[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// 增强版 handleAudio:支持封面图询问
|
// 新增:处理音频信息回复
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
async function handleAudioEnhanced(chatId: number, fileId: string, fileName?: string, mimeType?: string) {
|
async function handleAudioInfo(chatId: number, text: string): Promise<boolean> {
|
||||||
try {
|
|
||||||
const fs = await import("fs");
|
|
||||||
const path = await import("path");
|
|
||||||
const { getSession } = await import("./sessions");
|
|
||||||
|
|
||||||
const s = getSession(chatId);
|
|
||||||
if (!s.dirPath) {
|
|
||||||
await sendMessage(chatId, "❌ 请先发 /new 或 /edit 开始写作");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await sendMessage(chatId, "🎵 正在处理音频文件...");
|
|
||||||
|
|
||||||
// 获取文件
|
|
||||||
const fileRes = await tg<{ file_path?: string }>("getFile", { file_id: fileId });
|
|
||||||
if (!fileRes.ok || !fileRes.result?.file_path) {
|
|
||||||
await sendMessage(chatId, "❌ 音频文件获取失败");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filePath = fileRes.result.file_path;
|
|
||||||
const fileUrl = "https://api.telegram.org/file/bot" + TG_TOKEN + "/" + filePath;
|
|
||||||
const audioBuffer = await fetch(fileUrl).then(r => r.arrayBuffer());
|
|
||||||
|
|
||||||
// 保存音频文件
|
|
||||||
const articleDir = s.dirPath;
|
|
||||||
if (!fs.existsSync(articleDir)) fs.mkdirSync(articleDir, { recursive: true });
|
|
||||||
|
|
||||||
const ext = fileName?.split(".").pop() || filePath.split(".").pop() || "mp3";
|
|
||||||
const filename = Date.now() + "-music." + ext;
|
|
||||||
fs.writeFileSync(path.join(articleDir, filename), Buffer.from(audioBuffer));
|
|
||||||
|
|
||||||
// 询问歌曲信息
|
|
||||||
const session = getSession(chatId);
|
|
||||||
session._pendingAudio = { filename, fileId, name: null, artist: null };
|
|
||||||
|
|
||||||
await tg("sendMessage", {
|
|
||||||
chat_id: chatId,
|
|
||||||
text: `✅ 音频已保存:${filename}\n\n请输入歌曲信息(格式:歌名 - 歌手):`,
|
|
||||||
reply_markup: {
|
|
||||||
force_reply: true,
|
|
||||||
input_field_placeholder: "例如:晴天 - 周杰伦"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
console.error("[bot:audio]", e instanceof Error ? e.message : String(e));
|
|
||||||
await sendMessage(chatId, "❌ 音频处理失败:" + (e instanceof Error ? e.message : "未知错误"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// 增强版 handleAudioInfo:支持封面图询问
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
async function handleAudioInfoEnhanced(chatId: number, text: string): Promise<boolean> {
|
|
||||||
try {
|
try {
|
||||||
const { getSession } = await import("./sessions");
|
const { getSession } = await import("./sessions");
|
||||||
const s = getSession(chatId);
|
const s = getSession(chatId);
|
||||||
@@ -702,7 +621,6 @@ async function handleAudioInfoEnhanced(chatId: number, text: string): Promise<bo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析歌名和歌手
|
|
||||||
let name = "未知歌曲";
|
let name = "未知歌曲";
|
||||||
let artist = "未知艺术家";
|
let artist = "未知艺术家";
|
||||||
|
|
||||||
@@ -714,11 +632,9 @@ async function handleAudioInfoEnhanced(chatId: number, text: string): Promise<bo
|
|||||||
name = text.trim();
|
name = text.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存歌曲信息
|
|
||||||
s._pendingAudio.name = name;
|
s._pendingAudio.name = name;
|
||||||
s._pendingAudio.artist = artist;
|
s._pendingAudio.artist = artist;
|
||||||
|
|
||||||
// 询问是否添加封面图
|
|
||||||
await tg("sendMessage", {
|
await tg("sendMessage", {
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
text: `🎵 歌曲:${name}\n🎤 歌手:${artist}\n\n是否添加封面图?`,
|
text: `🎵 歌曲:${name}\n🎤 歌手:${artist}\n\n是否添加封面图?`,
|
||||||
@@ -739,7 +655,10 @@ async function handleAudioInfoEnhanced(chatId: number, text: string): Promise<bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理封面图选择回调
|
// ============================================================
|
||||||
|
// 新增:处理封面图选择回调
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
async function handleAudioCoverCallback(chatId: number, data: string) {
|
async function handleAudioCoverCallback(chatId: number, data: string) {
|
||||||
try {
|
try {
|
||||||
const { getSession } = await import("./sessions");
|
const { getSession } = await import("./sessions");
|
||||||
@@ -751,7 +670,6 @@ async function handleAudioCoverCallback(chatId: number, data: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data === "audio_skip_cover") {
|
if (data === "audio_skip_cover") {
|
||||||
// 跳过封面图,直接生成音乐卡片
|
|
||||||
const { filename, name, artist } = s._pendingAudio;
|
const { filename, name, artist } = s._pendingAudio;
|
||||||
delete s._pendingAudio;
|
delete s._pendingAudio;
|
||||||
|
|
||||||
@@ -762,7 +680,17 @@ async function handleAudioCoverCallback(chatId: number, data: string) {
|
|||||||
|
|
||||||
📌 歌曲:${name}
|
📌 歌曲:${name}
|
||||||
🎤 歌手:${artist}`, { parse_mode: "HTML" });
|
🎤 歌手:${artist}`, { parse_mode: "HTML" });
|
||||||
|
|
||||||
} else if (data === "audio_add_cover") {
|
} else if (data === "audio_add_cover") {
|
||||||
// 等待用户发送封面图
|
await tg("sendMessage", {
|
||||||
await tg("sendMessag
|
chat_id: chatId,
|
||||||
|
text: "🖼️ 请发送封面图片:",
|
||||||
|
reply_markup: {
|
||||||
|
force_reply: true,
|
||||||
|
input_field_placeholder: "发送一张图片作为封面"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[bot:audio-cover-callback]", e instanceof Error ? e.message : String(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user