| 289 | `); |
| 290 | |
| 291 | class ConvertPlugin extends Plugin { |
| 292 | cleanup(): void { |
| 293 | GeminiConfigManager.cleanup(); |
| 294 | } |
| 295 | |
| 296 | description: string = help_text; |
| 297 | |
| 298 | cmdHandlers: Record<string, (msg: Api.Message) => Promise<void>> = { |
| 299 | convert: async (msg: Api.Message) => { |
| 300 | const parts = msg.text?.trim()?.split(/\s+/) || []; |
| 301 | const args = parts.slice(1); |
| 302 | const subCommand = (args[0] || "").toLowerCase(); |
| 303 | |
| 304 | try { |
| 305 | if (subCommand === "help" || subCommand === "h" || args.length === 0 && !msg.replyTo) { |
| 306 | await msg.edit({ text: help_text, parseMode: "html" }); |
| 307 | } else if (subCommand === "clear") { |
| 308 | await this.handleClearCommand(msg); |
| 309 | } else if (subCommand === "apikey") { |
| 310 | await this.handleApiKeyCommand(msg, args.slice(1).join(" ")); |
| 311 | } else { |
| 312 | await this.handleVideoConversion(msg, args); |
| 313 | } |
| 314 | } catch (error: any) { |
| 315 | console.error("[convert] Plugin execution failed:", error); |
| 316 | await msg.edit({ |
| 317 | text: `❌ <b>插件执行失败:</b> ${htmlEscape(error.message)}`, |
| 318 | parseMode: "html" |
| 319 | }); |
| 320 | } |
| 321 | } |
| 322 | }; |
| 323 | |
| 324 | private async handleVideoConversion(msg: Api.Message, args: string[]): Promise<void> { |
| 325 | const client = await getGlobalClient(); |
| 326 | const reply = await safeGetReplyMessage(msg); |
| 327 | |
| 328 | if (!client || !reply || (!reply.document && !reply.video)) { |
| 329 | await msg.edit({ text: `❌ <b>使用错误</b>\n\n请回复一个视频消息后再使用此命令。\n\n请回复一个视频消息后再试。`, parseMode: "html" }); |
| 330 | return; |
| 331 | } |
| 332 | |
| 333 | const doc = reply.video || reply.document; |
| 334 | const fileNameAttr = doc?.attributes?.find((a: any) => a.fileName) as Api.DocumentAttributeFilename | undefined; |
| 335 | const originalFileName = fileNameAttr?.fileName || "video.mp4"; |
| 336 | |
| 337 | await msg.edit({ text: "📥 正在下载视频...", parseMode: "html" }); |
| 338 | |
| 339 | const timestamp = Date.now(); |
| 340 | const tempVideoPath = path.join(converter.tempDir, `${timestamp}_video`); |
| 341 | const tempAudioPath = path.join(converter.tempDir, `${timestamp}.mp3`); |
| 342 | let finalAudioPath = tempAudioPath; |
| 343 | let tempCoverPath: string | undefined; |
| 344 | |
| 345 | try { |
| 346 | await client.downloadMedia(reply, { outputFile: tempVideoPath }); |
| 347 | if (!fs.existsSync(tempVideoPath)) throw new Error("视频下载失败"); |
| 348 |
nothing calls this directly
no test coverage detected