# 媒體落地

各平台的 `Save` 方法把收到的檔案下載到指定目錄，並回傳存檔路徑。

## 簽名

```go
// core/telegram — fileID 取自 Input.Photo[i].FileID 或 Input.Document.FileID
func (b *Bot) Save(ctx context.Context, fileID, dir string) (string, error)

// core/discord — Input.Attachments 的其中一筆
func (b *Bot) Save(ctx context.Context, att *discordgo.MessageAttachment, dir string) (string, error)

// core/line — image、video、audio 或 file 訊息的 Input.MessageID
func (b *Bot) Save(ctx context.Context, messageID, dir string) (string, error)
```

## 各平台行為

| | Telegram | Discord | LINE |
|---|---|---|---|
| 大小上限 | 20 MiB（Bot API `getFile` 上限） | 25 MiB | 50 MiB（函式庫自訂上限） |
| 下載前得知大小 | `GetFile` → `FileSize` | `att.Size` | `ContentLength` |
| 下載方式 | 以 `http.DefaultClient` 取 `FileDownloadLink` | 以 `http.DefaultClient` 取 `att.URL` | `GetMessageContent` 串流 |
| 副檔名 | 取自 Telegram 的 `file_path` | 取自 `att.Filename` | 依回應的 `Content-Type` 推得 |

## 共通步驟

1. 空參數（`fileID`／`att`／`att.URL`／`messageID` 與 `dir`）直接回 error。
2. 回報的大小超過上限時，不下載直接回 error。
3. HTTP 狀態非 200（Telegram、Discord）時回傳 `http <code>: <body>`，body 最多 8 KiB。
4. 以 `os.MkdirAll(dir, 0755)` 建立 `dir`。
5. 串流寫入 `dir` 內的暫存檔 `<uuid>.*.tmp`，最多讀取上限 + 1 bytes。實際內容超過上限（回報大小缺漏或錯誤）時刪除暫存檔並回 error；超過上限的檔案不會被截斷保存。
6. 把暫存檔 rename 為 `<uuid><ext>`，回傳完整路徑。

檔名是 `go-pkg/utils` 產生的 v4 UUID；UUID 為空（亂數來源失敗）時回 error。Telegram／Discord 的原始檔名不保留；LINE file 訊息的原始檔名在 `Input.FileName`。

## LINE 副檔名對應

`image/jpeg` → `.jpg`、`image/png` → `.png`、`image/gif` → `.gif`、`image/webp` → `.webp`、`video/mp4` → `.mp4`、`audio/mp4` 與 `audio/x-m4a` → `.m4a`、`audio/aac` → `.aac`、`application/pdf` → `.pdf`。其他類型取 `mime.ExtensionsByType` 的第一個副檔名；未知類型不加副檔名。

## 範例

```go
bot.Reply(func(ctx context.Context, in discord.Input) string {
    for _, att := range in.Attachments {
        path, err := bot.Save(ctx, att, "./uploads")
        if err != nil {
            return "save failed: " + err.Error()
        }
        log.Println("saved", path)
    }
    return ""
})
```

## 相關頁面

- [Telegram 設定](/zh/telegram)（`Input.Photo`、`Input.Document`）
- [Discord 設定](/zh/discord)（`Input.Attachments`）
- [LINE 訊息](/zh/line-messages)（媒體訊息事件）
