当前位置:首页 > 旅游 > 正文

在一起365发抖音视频,用Go语言记录我们的爱情代码

  • 旅游
  • 2026-06-28 16:54:08
  • 747
摘要: 从一条抖音开始的故事说实话,我从来没想过自己会写这么一篇文章,但昨天,当我用Go语言写了个小工具,自动把我和女朋友在一起365天...

从一条抖音开始的故事

说实话,我从来没想过自己会写这么一篇文章,但昨天,当我用Go语言写了个小工具,自动把我和女朋友在一起365天的照片做成了抖音视频,发出去之后居然有几千人点赞,评论区炸了,都在问“代码能不能分享一下”,我突然觉得,用程序员的浪漫方式记录生活,这事儿还挺有意思的。

你可能觉得,写代码和拍抖音扯不上关系,但如果你像我一样,是个每天和Go语言打交道的程序员,又恰好想给另一半一个特别的纪念,那么你一定会爱上这个点子,我想用最直白的方式,把整个思路讲给你听——不是那种故作高深的教程,而是像朋友聊天一样,一边想一边写出来。

为什么是Go语言而不是Python?

先别急着用Python,我知道很多人一提到自动化处理视频,第一反应就是Python,但说句实话,Go在处理大量文件操作、并发任务、以及最终编译成单一可执行文件这几件事上,真的比Python顺手太多了。

我一开始也想用Python写,但后来发现,女朋友发来的365张照片,每张都要读取、检查格式、压缩、生成视频帧,如果按顺序一张一张处理,得等到猴年马月,Go的goroutine天然适合干这种“一堆事情一起做”的活儿。

更要命的是,Python要部署给别人用,得让对方装Python环境,而Go编译出来就是个二进制文件,双击就能跑,我女朋友的电脑上连Python是什么都不知道,但她能双击我给的video_maker.exe——这就够了。

核心思路:把照片变成视频,再用FFmpeg加点料

说白了,我们干的事情就是:读取365张照片 → 按日期排序 → 逐帧生成视频 → 加上文案和背景音乐 → 输出成mp4 → 自动发抖音

这里面有几个关键步骤,我踩了不少坑,现在一个个说清楚。

第一步:照片管理和命名规范

你得有365张照片,这不是废话,我女朋友的手机里存了上千张,但我们要选的是每天一张,我写了个Go程序,读取她手机备份里的照片,按照拍摄日期自动分组,然后从每一天的组里选一张——选哪张?我们用了个简单粗暴的方法:选文件大小最大的那张,因为通常拍得越认真,照片体积越大。

代码大概长这样:

type Photo struct {
    Path string
    Date time.Time
    Size int64
}

然后按日期分组,取每组里Size最大的,这个逻辑我写在了一个叫picker.go的文件里,读取目录,处理EXIF信息——这里要用到一个叫github.com/rwcarlsen/goexif/exif的库,第一次用的时候我差点崩溃,因为有些照片EXIF信息是空的,后来我加了层fallback,读不到EXIF就用文件修改时间。

第二步:生成视频帧

这件事比我想象的复杂,一开始我直接用Go往视频文件里写二进制数据,写了半天发现,Go的标准库里没有直接生成MP4的能力,后来我妥协了——用Go生成FFmpeg命令,然后让系统调用FFmpeg干活。

但这里有个窍门:不要生成一条超长的FFmpeg命令,那样会超出命令行长度限制,我把所有照片的路径写到一个临时文件里,然后让FFmpeg读这个文件。

实现方式是:

  • 创建一个filelist.txt,格式是file '/path/to/photo1.jpg'
  • 每一行后面加个duration 0.5,这样每张照片显示0.5秒
  • 加上一个crossfade效果,让转场不那么生硬

注意,durationcrossfade不能同时用,这是个坑,我查了半天文档才发现,需要先做一个无转场的视频,再用FFmpeg的xfade滤镜叠加转场,代码写起来像这样:

cmd := exec.Command("ffmpeg",
    "-f", "concat",
    "-safe", "0",
    "-i", filelistPath,
    "-vf", "fps=24",
    "-c:v", "libx264",
    tempVideoPath,
)

然后第二次调用FFmpeg,在头尾加上“365天”的文字水印和你想要的背景音乐。

第三步:加文字和音乐——这是灵魂

纯照片拼接的视频太单调了,我女朋友喜欢抖音上那种“小清新”风格:文字淡入淡出,音乐温柔但有点节奏。

文字我用的是FFmpeg的drawtext滤镜,这里注意中文字体问题——Windows上默认字体可能不支持中文,我手动指定了fontfile=C:/Windows/Fonts/msyh.ttc(微软雅黑),文字内容是写在Go代码里的,第1天”、“第100天”、“第365天”,我还在每张照片的右下角加了个小日期戳,用的strftime格式。

音乐方面,我用了一首免版权的钢琴曲,叫《With You》,直接在Go里读取music.mp3文件,混流进视频。

第四步:自动发抖音——这步最骚

视频做好了,怎么发到抖音?手动上传太low了,我研究了一下抖音的API,发现它没有公开的上传接口。—有个叫“抖音开放平台”的东西,申请之后可以用OAuth2.0授权,然后通过接口发布视频。

具体流程是:

  1. 在抖音开放平台创建应用,拿到client_idclient_secret
  2. 获取用户授权码(这一步需要手动扫码一次,以后可以自动刷新token)
  3. 调用/video/upload/接口上传文件
  4. 调用/video/create/接口填写标题和话题标签

这里有个细节:上传文件接口需要multipart/form-data格式,Go的net/http包原生支持,写起来很简单,但要注意设置Content-Type时不要手动拼字符串,用mime/multipart包生成。

我写了个tiktok_uploader.go,核心函数叫PostVideo,参数是视频文件路径、标题字符串,标题里自动加上“#我们的一周年 #365天挑战”之类的标签,这个函数里还处理了token过期自动刷新,因为抖音的access_token有效期只有7天。

第五步:定时任务——让浪漫自动化

你可能会问,难道每天都手动跑一遍程序?当然不是,我用Go写了个cron风格的调度器,每天凌晨2点执行一次(因为那时候服务器负载低,而且我女朋友肯定在睡觉,不会发现我在偷偷搞事情)。

调度器检查当天的日期,如果是365天中的某一天,就执行上述流程,如果哪一天照片没找到,它会发一条Slack消息通知我,让我手动补一张。

我用了github.com/robfig/cron/v3这个库,代码就几行:

c := cron.New()
c.AddFunc("0 2 * * *", func() {
    makeDailyVideo()
    uploadToTikTok()
})
c.Start()

踩坑记录与优化

没有哪段代码是一次写成的,我得坦白,这个项目我翻车了至少三次。

第一次翻车:照片顺序乱了。 因为Go读取目录文件的时候,默认是按文件名排序的,而我的照片文件名是“IMG_20230101.jpg”这种格式,问题在于,有些照片是晚上拍的,日期跨天了,但文件名还是前一天的,最后我用EXIF里的DateTimeOriginal字段重新排序,问题解决。

第二次翻车:视频太大。 365张照片,每张1920×1080,压缩之后仍然有300多MB,抖音上传限制是4GB,但手机端下载太慢了,我优化了压缩参数,把码率从15M降到5M,画质肉眼看不出来差别,体积降到了80MB。

第三次翻车:token失效。 在我出差那几天,程序突然不跑了,查日志发现是access_token过期了,刷新token的代码有个bug——刷新函数里把新token写到了全局变量,但调度器里的协程读的是旧值,后来我用sync.RWMutex加锁,问题解决。

用到的库和工具一览

库/工具 作用 版本
FFmpeg 视频编码、文字叠加、混流 0
goexif 读取照片EXIF信息 v2.0
cron 定时调度 v3
mime/multipart 文件上传编码 标准库
net/http HTTP客户端请求 标准库
encoding/json 解析API返回 标准库
抖音开放平台SDK 获取token和发布视频 v1.4.2

FFmpeg需要单独安装,其他都是Go模块,go get一下就行。

给想做这件事的人几点建议

第一,备份工作要做好,我女朋友的手机照片是自动同步到iCloud的,但程序读的是她电脑上的本地文件夹,我写了个文件同步函数,每次运行之前先检查本地和云端的差异,把缺失的照片下载下来。

第二,生成视频的过程大概需要15分钟(取决于CPU性能)。不要在手机上跑,那会烫得能煎鸡蛋,在服务器或者你的开发机上跑就好。

第三,如果女朋友问起来,别告诉她代码怎么写的,我直接跟她说“我写了个魔法”,她开心得不行,浪漫不需要解释原理。

代码之外的感悟

说实话,写这个程序花的功夫,比写业务代码多多了,但当你看到那365张照片像放电影一样闪过,想起第一张照片是她在医院实习时拍的,第一百张是在海边,第三百六十五张是我们一起做蛋糕——那一刻你会觉得,值了。

而且你知道吗?她后来又偷偷用我写的程序,把我们第二个365天的视频也做出来了,她不懂Go,但她会双击那个exe文件,这就够了。

如果你也想试试,从今天开始,每天存一张照片,一年之后,用Go写个程序,把那些碎片拼成一段视频,发到抖音上,配文就写“在一起365天,这是代码写的,也是真心写的。”

你的代码可以编译、分享、改进,就像你们的感情一样。

在一起365发抖音视频,用Go语言记录我们的爱情代码