(msg: Api.Message, targetPath?: string)
| 543 | await msg.edit({ text: `用法: ${commandName} setport [端口号]` }); |
| 544 | return; |
| 545 | } |
| 546 | |
| 547 | const installPath = await this.detectInstalledPath(); |
| 548 | const configPath = `${installPath}/data/config.json`; |
| 549 | if (!(await this.fileExists(configPath))) { |
| 550 | await msg.edit({ text: "未找到配置文件,请先确保 OpenList 已成功运行一次。" }); |
| 551 | return; |
| 552 | } |
| 553 | |
| 554 | await msg.edit({ text: `正在修改端口为 ${port}...` }); |
| 555 | await execAsync(`systemctl stop openlist || true`); |
| 556 | // 使用 sed 安全地替换端口号 |
| 557 | await execAsync( |
| 558 | `sed -i 's/"port": *[0-9]*/"port": ${port}/g' "${configPath}"` |
| 559 | ); |
| 560 | await execAsync(`systemctl start openlist`); |
| 561 | |
| 562 | await msg.edit({ text: `端口已修改为 ${port},服务已重启。` }); |
| 563 | } catch (error: any) { |
| 564 | await msg.edit({ text: `端口修改失败: ${error?.message || error}` }); |
| 565 | } |
| 566 | } |
| 567 | |
| 568 | private async handleSave(msg: Api.Message, targetPath?: string) { |
| 569 | try { |
| 570 | const replyToMsg = await safeGetReplyMessage(msg); |
| 571 | if (!replyToMsg || !replyToMsg.media) { |
| 572 | await msg.edit({ text: "请回复一个文件、图片或视频来保存。" }); |
| 573 | return; |
| 574 | } |
| 575 | |
| 576 | // 确定最终保存路径 |
| 577 | let finalPath = targetPath; |
| 578 | if (!finalPath) { |
| 579 | // 尝试读取默认路径 |
| 580 | const db = await this.getDb(); |
| 581 | finalPath = db.data.defaultPath || ""; |
| 582 | } |
| 583 | |
| 584 | const media = replyToMsg.media; |
| 585 | let fileName = ""; |
| 586 | |
| 587 | if (media instanceof Api.MessageMediaPhoto) { |
| 588 | fileName = `photo_${Date.now()}.jpg`; |
| 589 | } else if (media instanceof Api.MessageMediaDocument && media.document instanceof Api.Document) { |
| 590 | const doc = media.document; |
| 591 | const fileNameAttr = doc.attributes.find( |
| 592 | (attr): attr is Api.DocumentAttributeFilename => |
| 593 | attr instanceof Api.DocumentAttributeFilename |
| 594 | ); |
| 595 | |
| 596 | if (fileNameAttr) { |
| 597 | fileName = sanitizeMediaFileName(fileNameAttr.fileName); |
| 598 | } else { |
| 599 | // 根据 mimeType 推断后缀 |
| 600 | let ext = ""; |
| 601 | switch (doc.mimeType) { |
| 602 | case "video/mp4": ext = ".mp4"; break; |
no test coverage detected