说实话,我一开始根本没想到要把365dni、百度网盘和西瓜视频这三个东西搅和到一块儿,事情是这样的:我去年偶然发现365dni这个资源集合,里面塞满了各种视频文件,甚至还有一些文档和图片,我寻思着把这片乱七八糟的玩意儿整理到百度网盘里,结果发现手动操作简直要命——一个文件夹一个文件夹地上传,眼睛都快瞎了,更别提后来我想从西瓜视频里扒点素材,却发现自己连文件格式都理不顺。
我决定用Golang写个小工具,把这些乱七八糟的事情自动化,别急着觉得我多厉害,其实我就一普通码农,爱好就是瞎折腾,这篇文章就是我折腾的过程,希望能帮你少走点弯路。
为什么要用Golang处理365dni和百度网盘?
先说说我的需求,365dni这个资源包,我估计有些人知道,里面文件多得吓人,大概有:
- 视频文件(.mp4, .avi, .mkv)
- 文本文件(.txt, .pdf)
- 图片文件(.jpg, .png)
- 还有一些乱七八糟的压缩包
我需要:
- 把这些文件按类型分类,比如视频丢一个文件夹,文档丢另一个。
- 重命名文件,避免百度网盘里出现“新建文件夹(1)”这种鬼名字。
- 批量上传到百度网盘,最好是自动化的。
- 顺便从西瓜视频下载一些公开素材,合并到我的库里。
手动搞?别逗了,光数文件就能让我崩溃,用Python?也行,但我更喜欢Golang的编译速度和并发处理能力——毕竟文件多了,单线程跑起来能急死人。
我的Golang环境搭建
如果你也想试试,先装好Go,我用的版本是1.21,其实1.18以上估计都行,装好之后,记得设好GOPATH,不然你拉包的时候会哭。
go version # 输出类似 go version go1.21.0 linux/amd64
工具结构就是:
my-tool/
├── main.go # 主入口
├── file-sorter.go # 文件分类逻辑
├── baidupan.go # 百度网盘API交互
├── xigua.go # 西瓜视频相关处理
└── utils.go # 通用函数
第一步:处理365dni的文件混乱
我遇到的第一个坑是文件编码问题,365dni里有些文件名是中文的,但编码居然是GBK,而我的系统是UTF-8,结果一扫描,文件名全变成乱码,Golang里处理这个很简单,用golang.org/x/text/encoding/charmap就能转码。
我写了一个小函数:
func fixFilename(name string) string {
// 尝试GBK解码
decoder := charmap.GBK.NewDecoder()
result, err := decoder.String(name)
if err != nil {
// 解码失败说明可能已经是UTF-8
return name
}
return result
}
我需要遍历365dni文件夹里的所有文件,按类型放到对应子目录里,Golang的filepath.Walk函数比我预期的更容易,配合协程(goroutine)处理多个文件,速度杠杠的。
func classifyFiles(root string) {
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 忽略目录本身
if info.IsDir() {
return nil
}
// 根据后缀决定移动策略
ext := filepath.Ext(info.Name())
switch ext {
case ".mp4", ".avi", ".mkv":
// 视频文件放入video文件夹
moveFile(path, filepath.Join(root, "video", info.Name()))
case ".txt", ".pdf", ".docx":
moveFile(path, filepath.Join(root, "doc", info.Name()))
// ... 其他类型类似
}
return nil
})
}
你可能会问:为什么不用现成的工具?比如Python的os模块也行啊,对,但我的机器上Python装了三个版本,依赖冲突搞死我了,Go的好处是编译后一个二进制文件,扔到哪都能跑,不依赖乱七八糟的环境,尤其是我以后想把工具分享给朋友,直接给他exe就行,省心。
一个小插曲:处理超大文件
365dni里有几个视频文件超过10GB,移动的时候我差点把硬盘写爆,后来我改用符号链接(symlink)而不是直接复制,省了空间也快了。
func moveFile(src, dst string) error {
// 先尝试建立硬链接,保留原文件
err := os.Link(src, dst)
if err != nil {
// 如果硬链接失败(比如跨磁盘),就复制
return copyFile(src, dst)
}
// 成功后删除原文件(看需求)
os.Remove(src)
return nil
}
不过要注意,百度网盘客户端对符号链接支持不好,所以我最后还是统一用了复制,复制大文件时记得用缓冲区,别一次性读内存里:
func copyFile(src, dst string) error {
srcFile, _ := os.Open(src)
defer srcFile.Close()
dstFile, _ := os.Create(dst)
defer dstFile.Close()
buf := make([]byte, 1024*1024) // 1MB缓存
_, err := io.CopyBuffer(dstFile, srcFile, buf)
return err
}
第二步:对接百度网盘API
百度网盘的官方API文档写得还行,但实际用起来坑不少,你得先去百度网盘开放平台注册一个应用,拿到AppID、AppKey、SecretKey,然后走OAuth2授权流程——这过程我折腾了一下午,主要是不理解“access_token”的有效期只有30天,而我忘了设定时刷新。
Golang有现成的库,比如github.com/iikira/BaiduPCS-Go,但那个库是基于命令行的,我直接用了官方SDK的Go版(其实百度官方没有纯Go SDK,但我找了个社区维护的baidubce-sdk-go)。
核心代码大概这样:
func uploadToBaiduPan(filePath string) error {
client := baidubce.NewClient(
baidubce.WithAccessKey("your-access-key"),
baidubce.WithSecretKey("your-secret-key"),
)
// 构建上传请求
req := &baidubce.BosPutObjectRequest{
Bucket: "your-bucket",
Key: "365dni/" + filepath.Base(filePath), // 远程路径
Body: getFileReader(filePath),
}
_, err := client.Bos.PutObject(req)
return err
}
这个逻辑看起来简单,但实际跑起来我遇到一个问题:百度网盘服务器对并发请求有限制,我同时传20个文件,结果一半失败,解决方案就是加一个令牌桶限流:
var limiter = rate.NewLimiter(2, 1) // 每秒最多2个上传
func rateLimitedUpload(filePath string) {
for {
err := limiter.Wait(context.Background())
if err != nil {
time.Sleep(100 * time.Millisecond)
continue
}
// 执行上传
if uploadToBaiduPan(filePath) == nil {
break
}
}
}
关于文件结构的保存
我还在百度网盘里建了多级目录分类,
365dni/视频/2023/365dni/文档/技术/365dni/图片/生活/
这些目录结构我是从365dni原文件的标签信息里提取的,有些文件夹名字里带有[2023]这种标志,我就用正则匹配:
func extractYear(dirName string) string {
re := regexp.MustCompile(`\[(\d{4})\]`)
match := re.FindStringSubmatch(dirName)
if len(match) > 1 {
return match[1]
}
return "unknown"
}
第三步:西瓜视频素材的抓取与合并
这部分比较敏感,但我不是做盗版,只是下载西瓜视频上一些公开的、无版权的素材,比如风景片段、教程类视频——这些作者允许转载,我个人用Golang写了一个简易下载器,基于github.com/iawia002/annie(现在叫lux)的库,但lux不支持西瓜视频新接口,所以我改用了直接模拟请求。
西瓜视频的视频链接通常是m3u8格式的,需要先解析m3u8获取.ts分片文件列表,然后下载合并,Golang里用github.com/grafov/m3u8库来解析:
func parseM3U8(url string) ([]string, error) {
resp, _ := http.Get(url)
defer resp.Body.Close()
pl, _ := m3u8.NewDecoder(resp.Body).Decode()
playlist := pl.(*m3u8.MediaPlaylist)
segs := make([]string, len(playlist.Segments))
for i, seg := range playlist.Segments {
segs[i] = seg.URI
}
return segs, nil
}
但m3u8里的分片路径往往是相对路径,需要拼接成完整URL,我踩坑就是忘了处理这个,下载了一堆空文件。
合并.ts成mp4用ffmpeg命令最方便,但在Go里直接调用外部命令不太优雅,我用github.com/u2takey/ffmpeg-go这个库,它能调用系统安装的ffmpeg:
func mergeTS(segments []string, output string) error {
// 先创建一个文件列表
listFile := "segments.txt"
f, _ := os.Create(listFile)
for _, seg := range segments {
f.WriteString("file '" + seg + "'\n")
}
f.Close()
// 用ffmpeg合并
err := ffmpeg_go.Input(listFile, ffmpeg_go.KwArgs{"f": "concat", "safe": "0"}).
Output(output, ffmpeg_go.KwArgs{"c": "copy"}).
OverWriteOutput().Run()
return err
}
下载完的西瓜视频素材,我统一丢到365dni的素材文件夹里,再跟百度网盘同步,这样我手机上看西瓜视频时遇到喜欢的片段,就能一键保存到网盘里,跨平台自由访问。
嘘,假装没有总结,继续往下看)
工具写完后,我整个流程从手动操作一周,降到了全自动20分钟,我只需要把365dni资源解压到指定目录,然后运行go run main.go,剩下的事儿我的小代码就全包了,百度网盘里文件井井有条,西瓜视频素材随时更新——这小工具成了我私人的“媒体处理系统”。
代码写得不算完美,比如错误处理我就没太周全,有些地方甚至panic了,但这不重要,关键它帮我干了最烦人的重复劳动,你要是也想试试,从github.com/fatih/go-file-utils之类的库开始也行,反正用Golang搞文件管理,就是爽——编译快、并发强、部署简单。

工具发到朋友群里,他们都说“你这坨东西不就是个半成品嘛,缺这缺那的”,我就笑了,半成品怎么了?能干活就行啊,反正对我这种普通人来说,工具能让我少加几次班、多刷几部西瓜视频,就是好工具。
至于365dni里剩下的乱码文件夹,哎,慢慢修吧,毕竟写代码这事儿,永远有Bug等着你——这大概就是生活的味道。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://www.hljbesthome.com/keji/888.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《365dni、百度网盘和西瓜视频,我用Golang折腾文件管理的那点事》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:说实话,我一开始根本没想到要把365dni、百度网盘和西瓜视频这三个东西搅和到一块儿,事情是这样的:我去年偶然发现365dni这个资源集...