aboutsummaryrefslogtreecommitdiffstats
path: root/internal/download
diff options
context:
space:
mode:
authorfengnightstarts <fengnightstarts@users.noreply.github.com>2026-02-12 16:24:54 +0800
committerfengnightstarts <fengnightstarts@users.noreply.github.com>2026-02-12 16:24:54 +0800
commitb665cb604ac5ad9322b536c4de7334ae2efd84dc (patch)
treeeee8cdfc82bd03f2e4b464e4ca66738f7cc5dc81 /internal/download
parentc52f41545df179b542f106d08e6dd013a70216e7 (diff)
downloadbvd-b665cb604ac5ad9322b536c4de7334ae2efd84dc.tar.gz
bvd-b665cb604ac5ad9322b536c4de7334ae2efd84dc.zip
feat: 修复下载错误并添加输出路径选项
- 修复 B站 API 返回 412 错误:添加 User-Agent 和 Referer 请求头 - 新增 -f/--file 参数:指定单个视频的输出文件名 - 新增 -d/--director 参数:指定下载目标文件夹(自动创建不存在的目录) - 添加 DownloadOptions 结构体支持灵活的下载配置
Diffstat (limited to 'internal/download')
-rw-r--r--internal/download/downloader.go39
1 files changed, 33 insertions, 6 deletions
diff --git a/internal/download/downloader.go b/internal/download/downloader.go
index 24a91db..e89c23c 100644
--- a/internal/download/downloader.go
+++ b/internal/download/downloader.go
@@ -10,14 +10,25 @@ import (
"path/filepath"
)
+type DownloadOptions struct {
+ OutputFile string // 单个视频下载时的输出文件名
+ OutputDir string // 下载目标文件夹
+}
+
type Downloader struct{}
func NewDownloader() *Downloader {
return &Downloader{}
}
-func requestSend(urls []string, video *api.VideoBaseInfo) error {
+func requestSend(urls []string, video *api.VideoBaseInfo, opts *DownloadOptions) error {
+ // 确定下载目录
downloadDir := "./downloads/"
+ if opts != nil && opts.OutputDir != "" {
+ downloadDir = opts.OutputDir
+ }
+
+ // 创建下载目录
if err := os.MkdirAll(downloadDir, 0755); err != nil {
return fmt.Errorf("❌ 创建下载目录失败:%w", err)
}
@@ -53,7 +64,14 @@ func requestSend(urls []string, video *api.VideoBaseInfo) error {
}
// 构建文件名
- filename := filepath.Join(downloadDir, video.Data[i].Part+".mp4")
+ var filename string
+ if opts != nil && opts.OutputFile != "" {
+ // 使用用户指定的文件名
+ filename = filepath.Join(downloadDir, opts.OutputFile+".mp4")
+ } else {
+ // 使用视频分P名称作为文件名
+ filename = filepath.Join(downloadDir, video.Data[i].Part+".mp4")
+ }
fmt.Printf("✅ 保存到: %s\n", filename)
// 创建文件
@@ -81,7 +99,7 @@ func requestSend(urls []string, video *api.VideoBaseInfo) error {
return nil
}
-func (d *Downloader) Start(bvid string, apiClient *api.BiliAPI) error {
+func (d *Downloader) Start(bvid string, apiClient *api.BiliAPI, opts *DownloadOptions) error {
fmt.Println("✅ 获取到 BV 号:", bvid)
videoInfo, err := apiClient.GetVideoInfo(bvid)
@@ -103,9 +121,18 @@ func (d *Downloader) Start(bvid string, apiClient *api.BiliAPI) error {
for j, cid := range cids {
apiUrl := fmt.Sprintf("https://api.bilibili.com/x/player/playurl?&cid=%d&bvid=%s&qn=80", cid, bvid)
- resp, err := apiClient.Client.Get(apiUrl)
+ req, err := http.NewRequest("GET", apiUrl, nil)
+ if err != nil {
+ return fmt.Errorf("❌ CID %d 创建请求失败: %w", cid, err)
+ }
+
+ req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
+ req.Header.Set("Referer", fmt.Sprintf("https://www.bilibili.com/video/%s", bvid))
+
+ resp, err := apiClient.Client.Do(req)
+
if err != nil {
- return fmt.Errorf("❌ CID %d 请求 请求失败: %w", cid, err)
+ return fmt.Errorf("❌ CID %d 请求失败: %w", cid, err)
}
body, err := io.ReadAll(resp.Body)
@@ -135,7 +162,7 @@ func (d *Downloader) Start(bvid string, apiClient *api.BiliAPI) error {
fmt.Println("✅ 获取到所有下载链接")
- requestSend(downloadUrls, videoInfo)
+ requestSend(downloadUrls, videoInfo, opts)
return nil
}