2032
This commit is contained in:
1 parent
56ea059fc0
commit
e3ef5e6767
3 files changed
+55
-19
No files matched your search
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/types/routes.d.ts";
|
import "./.next/dev/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
@@ -201,9 +201,7 @@ handlers.help = async (chatId) => {
|
|||||||
`├─ 🎙️ 语音消息:自动转文字 + 生成语音播放器`,
|
`├─ 🎙️ 语音消息:自动转文字 + 生成语音播放器`,
|
||||||
`├─ 🎵 MP3 文件:交互式问答生成音乐卡片`,
|
`├─ 🎵 MP3 文件:交互式问答生成音乐卡片`,
|
||||||
`├─ 📷 普通图片:直接插入文章`,
|
`├─ 📷 普通图片:直接插入文章`,
|
||||||
`├─ 📷 HEIC 图片(iOS 实况照片):`,
|
`├─ 📷 Live Photo(iOS HEIC):自动转换为视频 + 生成 livephoto 播放器`,
|
||||||
`│ └─ 动态效果无法自动提取`,
|
|
||||||
`│ └─ 需先转为 GIF/视频再发送`,
|
|
||||||
`├─ 🎬 视频/GIF:直接插入文章`,
|
`├─ 🎬 视频/GIF:直接插入文章`,
|
||||||
`└─ 📄 文档:保存到文章目录`,
|
`└─ 📄 文档:保存到文章目录`,
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
|
|||||||
@@ -502,13 +502,14 @@ async function handleAudioEnhanced(chatId: number, fileId: string, fileName?: st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// 新增:处理图片(增强版:支持封面图上传 + 实况照片引导)
|
// 新增:处理图片(增强版:支持封面图上传 + Live Photo 自动转换)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[], caption?: string) {
|
async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[], caption?: string) {
|
||||||
try {
|
try {
|
||||||
const fs = await import("fs");
|
const fs = await import("fs");
|
||||||
const path = await import("path");
|
const path = await import("path");
|
||||||
|
const { execSync } = await import("child_process");
|
||||||
const { getSession } = await import("./sessions");
|
const { getSession } = await import("./sessions");
|
||||||
|
|
||||||
const s = getSession(chatId);
|
const s = getSession(chatId);
|
||||||
@@ -536,27 +537,64 @@ async function handlePhotoEnhanced(chatId: number, photos: { file_id: string }[]
|
|||||||
if (!fs.existsSync(articleDir)) fs.mkdirSync(articleDir, { recursive: true });
|
if (!fs.existsSync(articleDir)) fs.mkdirSync(articleDir, { recursive: true });
|
||||||
|
|
||||||
const ext = filePath.split(".").pop() || "jpg";
|
const ext = filePath.split(".").pop() || "jpg";
|
||||||
const filename = Date.now() + "-" + largestPhoto.file_id.slice(0, 8) + "." + ext;
|
const baseFilename = Date.now() + "-" + largestPhoto.file_id.slice(0, 8);
|
||||||
fs.writeFileSync(path.join(articleDir, filename), Buffer.from(imgBuffer));
|
const filename = baseFilename + "." + ext;
|
||||||
|
const fullPath = path.join(articleDir, filename);
|
||||||
|
fs.writeFileSync(fullPath, Buffer.from(imgBuffer));
|
||||||
|
|
||||||
const imgCaption = caption || "image";
|
// HEIC 文件(iOS Live Photo)自动转换
|
||||||
appendContent(chatId, `\n\n`);
|
|
||||||
|
|
||||||
// 只对 HEIC 文件(iOS 实况照片)显示提示
|
|
||||||
const isHEIC = ext.toLowerCase() === "heic" || ext.toLowerCase() === "heif";
|
const isHEIC = ext.toLowerCase() === "heic" || ext.toLowerCase() === "heif";
|
||||||
if (isHEIC) {
|
if (isHEIC) {
|
||||||
await sendMessage(chatId, `📷 图片已保存:${filename}
|
await sendMessage(chatId, "🎞️ 检测到 Live Photo,正在转换为视频...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 转换 HEIC 为 MP4 视频
|
||||||
|
const videoFilename = baseFilename + ".mp4";
|
||||||
|
const videoPath = path.join(articleDir, videoFilename);
|
||||||
|
|
||||||
|
// 使用 ffmpeg 转换 HEIC 为 MP4(保持原有帧率和质量)
|
||||||
|
execSync(`ffmpeg -y -i "${fullPath}" -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p "${videoPath}"`, { timeout: 60000 });
|
||||||
|
|
||||||
|
// 提取第一帧作为封面图
|
||||||
|
const coverFilename = baseFilename + "-cover.jpg";
|
||||||
|
const coverPath = path.join(articleDir, coverFilename);
|
||||||
|
execSync(`ffmpeg -y -i "${videoPath}" -vframes 1 -q:v 2 "${coverPath}"`, { timeout: 30000 });
|
||||||
|
|
||||||
|
// 删除原始 HEIC 文件
|
||||||
|
fs.unlinkSync(fullPath);
|
||||||
|
|
||||||
|
// 生成 livephoto 短代码
|
||||||
|
const livePhotoShortcode = `\n\n{{< livephoto src="${videoFilename}" cover="${coverFilename}" >}}\n\n`;
|
||||||
|
appendContent(chatId, livePhotoShortcode);
|
||||||
|
|
||||||
|
await sendMessage(chatId, `✅ <b>Live Photo 转换完成!</b>
|
||||||
|
|
||||||
💡 <b>检测到 iOS 实况照片(HEIC 格式)</b>
|
📹 视频:${videoFilename}
|
||||||
|
🖼️ 封面:${coverFilename}
|
||||||
|
|
||||||
动态效果无法自动提取。如需保留动态效果,请:
|
已插入 livephoto 短代码,支持点击播放动态效果。`, { parse_mode: "HTML" });
|
||||||
|
|
||||||
|
return;
|
||||||
|
} catch (convertError) {
|
||||||
|
console.error("[bot:heic-convert]", convertError instanceof Error ? convertError.message : String(convertError));
|
||||||
|
// 转换失败,回退到普通图片处理
|
||||||
|
appendContent(chatId, `\n\n`);
|
||||||
|
await sendMessage(chatId, `📷 图片已保存:${filename}
|
||||||
|
|
||||||
|
⚠️ <b>Live Photo 转换失败</b>
|
||||||
|
|
||||||
|
动态效果无法提取,已作为普通图片插入。如需动态效果,请:
|
||||||
1. 在 iPhone 上使用「快捷指令」将实况照片转为 GIF
|
1. 在 iPhone 上使用「快捷指令」将实况照片转为 GIF
|
||||||
2. 或使用第三方 App 导出为视频后重新发送
|
2. 或使用第三方 App 导出为视频后重新发送`, { parse_mode: "HTML" });
|
||||||
|
return;
|
||||||
继续发送其他内容...</b>`, { parse_mode: "HTML" });
|
}
|
||||||
} else {
|
|
||||||
await sendMessage(chatId, `📷 图片已保存:${filename}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 普通图片处理
|
||||||
|
const imgCaption = caption || "image";
|
||||||
|
appendContent(chatId, `\n\n`);
|
||||||
|
await sendMessage(chatId, `📷 图片已保存:${filename}`);
|
||||||
|
|
||||||
} 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, "❌ 图片保存失败");
|
||||||
|
|||||||
Reference in new issue
Block a user