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

365天纸飞机AKB48视频,我用Golang写了一个循环播放器,结果把自己看哭了

  • 旅游
  • 2026-07-28 12:56:16
  • 35
摘要: 为什么突然想写这个?一个莫名其妙的冲动事情是这样的,上个月我整理硬盘,翻出一个叫“365天纸飞机AKB48视频”的文件夹,那是去...

为什么突然想写这个?一个莫名其妙的冲动

事情是这样的,上个月我整理硬盘,翻出一个叫“365天纸飞机AKB48视频”的文件夹,那是去年某个深夜,我蹲在B站刷到的一个挑战视频——有人坚持每天折一只纸飞机,背景音乐永远是AKB48的《365日の紙飛行機》,我当时觉得这事儿挺傻的,但出于某种奇怪的心理,我居然把那个系列视频全下载了。

然后我就在想:如果换成Golang来写一个程序,每天自动播放当天的视频片段,会是什么效果? 这个念头一冒出来,我就知道完蛋了——不写出来今晚别想睡觉。

先说说这个“365天纸飞机AKB48视频”到底是什么鬼

其实这个挑战挺简单的:一个人每天折一只纸飞机,对着镜头展示,背景放AKB48的《365日の紙飛行機》,但问题在于——你得坚持整整一年。

我数了数,下载下来的视频总共有:

  • 365个独立片段(一天一个,不重样)
  • 总时长大概是18小时47分钟
  • 每个片段长度从2分半到4分钟不等
  • 分辨率从480p到1080p都有(肉眼可见的伤心)

最离谱的是第213天那个视频,明显是凌晨3点拍的,折纸手都在抖,但背景音乐一直没断,这种倔强,说实话有点戳人。

用Golang写个播放器?一开始我觉得很简单

我最初的思路是:用Go写一个CLI程序,每天自动播放对应日期的视频文件,start、stop、pause基本操作就行。

代码最初长这样:

package main
import (
    "fmt"
    "os/exec"
    "strconv"
    "time"
)
func main() {
    day := time.Now().YearDay()
    fmt.Printf("今天是第 %d 天\n", day)
    filename := fmt.Sprintf("videos/day%03d.mp4", day)
    cmd := exec.Command("ffplay", "-autoexit", filename)
    cmd.Run()
}

跑起来倒是没问题,但看着黑漆漆的终端窗口,我感觉不对劲——这玩意儿跟折纸飞机本身一样单调。缺少仪式感

真正的挑战不在代码,在“人”

费曼说,如果你不能把一个概念解释清楚,说明你没真正理解它,我当时就卡在这个地方:我是想复制那个视频挑战的行为,还是想传递那种“坚持”的感觉?

我重新看了几段视频,重点不在折纸的动作上,而是:

  1. 背景音乐循环播放时的轻微变化(有时候是歌的高潮部分被剪进来了)
  2. 那人的手在折纸时的细微颤抖
  3. 每天视频结尾的一句话总结(有时是“今天工作好累”,有时是“这架飞机应该能飞到月球”)

这些东西才是灵魂,Golang代码写得再漂亮,也写不出那种感觉,但我至少可以让播放器尊重这些细节

第二版:带进度条和备注的播放器

我重写了代码,加入了两个关键功能:

显示当天视频的备注信息
我手动整理了所有视频的描述(从文件名里提取的注释部分),放在一个Go结构体里:

type DailyNote struct {
    Day   int
    Note  string
    Mood  string  // 情绪标签
}

进度条可视化
\r实现终端覆盖刷新效果,显示当天已经播放了多少:

func progressBar(current, total float64) string {
    width := 50
    filled := int((current / total) * float64(width))
    bar := strings.Repeat("=", filled) + strings.Repeat(" ", width-filled)
    return fmt.Sprintf("[%s] %.1f%%", bar, (current/total)*100)
}

这个进度条跑起来的时候,屏幕上一卡一卡地推进,配上那个循环的旋律——我突然觉得,这不就是在模拟时间本身吗?

为什么选Golang?不是因为它快,是因为它“笨”

说点实话,用Python写这个功能大概两小时就能搞定,Rust也行,但我选Go的理由有点怪:Golang的编译输出是一个静态二进制文件

我不需要装ffmpeg、不需要Python环境、不需要依赖管理,双击就能跑,而“365天纸飞机”这个挑战本质上就是一个人对时间的笨拙坚持——Go的静态编译气质正好和它吻合。

而且Go的os/exec包让我可以直接调用ffplay播放视频,输出控制台日志,很简陋但够用,那种“刚刚够用”的感觉,和视频里折纸飞机的动作很像——不需要多精致,只要每天做。

重构:加入日期选择器和跳跃播放

写完之后我发现一个问题:没人会真的每天打开这个程序,大多数人(包括我自己)都是一口气刷完整个系列。

所以我加了一个交互模式:

fmt.Println("选择操作:")
fmt.Println("1. 播放今天")
fmt.Println("2. 随机播放一天")
fmt.Println("3. 连续播放(从第一天到第365天)")

连续播放模式最离谱,我试了一次,从头放到尾,坐在那儿看了18个小时,到第100天左右的时候,视频里的人折纸越来越熟练,但背景音乐开始出现不同版本的翻唱。第187天居然用的是钢琴版

Golang的协程在这里帮了大忙——我可以同时启动时间显示、进度条、和下一个视频的预加载:

go func() {
    for {
        fmt.Printf("\r当前时间: %s | 进度: %s", 
            time.Now().Format("15:04:05"),
            progressBar(float64(day), 365.0))
        time.Sleep(1 * time.Second)
    }
}()

那封藏在第365天视频里的信

视频播到第365天的时候,我正靠在椅子上发呆,折纸的那个人——实际上我之前一直以为是个AI生成的账号——他展示完最后一只纸飞机后,突然开口说话了:

“这架飞机……是真的,我折了整整一年,有时候我想放弃,但音乐一直在,如果你看到这里,谢谢你陪我走过这365天。”

Golang程序还在跑,终端里循环着最后一段旋律,我感觉眼眶有点发酸。

赶紧关掉了程序,但那个画面和声音一直留在脑子里。

技术总结?不,只是记录一种状态

我现在电脑里还留着这个Go程序,偶尔打开,随机跳到某一天看看。

技术上没什么了不起的

  • 200行不到的Go代码
  • ffplay播放视频
  • time包处理时间
  • sync包管理并发

但每次跑起来,看到那个简陋的进度条在终端里往前爬,我就想起一件事:也许我们写代码的意义,有时候不是解决问题,而是记录一种状态

那个折纸飞机的人用365天证明了一件事——坚持不需要意义,坚持本身就是意义,而我用Golang把这个过程重新播放了一遍,虽然慢,虽然笨,但至少没弄丢。

最后说一句:如果你真想跑这个程序,别用别人的视频,自己拍365天,自己写代码,那才叫你的365天。

365天纸飞机AKB48视频,我用Golang写了一个循环播放器,结果把自己看哭了