用Go语言给孩子搭个365成语故事视频全集小工具?这活儿我干过
- 体育
- 2026-08-05 05:59:00
- 56
昨儿晚上我家那口子又念叨,说孩子天天抱着平板看动画片,不如看点有营养的——得,又是“365成语故事视频全集”这茬儿,我一边答应着,一边心里盘算:这玩意儿网上资源确实多,但零零散散,今天这个App有版权明天那个网站要会员,烦不烦?干脆,我用Go写个小工具,把家里存的那套《365成语故事视频全集》按目录规整起来,顺手还能生成个简单的播放列表页面,你别说,这事儿用Go干起来,真挺顺手。
为啥非得用Go?Python它不香吗?
说实话,Python写脚本是快,但咱这需求有点特殊:要处理视频文件的重命名、目录扫描、生成索引文件,而且将来可能还要挂个简单的HTTP服务,让孩子在平板上直接浏览器访问,Go编译出来就是个单个可执行文件,扔到NAS或者旧笔记本上就能跑,不依赖环境,内存占用还小——就冲这点,我选Go。
第一步:先把“365成语故事”这堆乱文件理清楚
我这套《365成语故事视频全集》是从网盘上拖下来的,文件名全是“第1集-画蛇添足.mp4”“第2集-自相矛盾.mp4”这种,但有些是“第003集-掩耳盗铃 (1).mp4”,还有些混着空格和括号,乱得很,我的目标是:统一成“001_画蛇添足.mp4”这种格式,顺便清理掉多余的括号和空格。
package main
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
)
func main() {
dir := "./365成语故事视频全集"
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if strings.HasSuffix(info.Name(), ".mp4") {
newName := renameVideo(info.Name())
if newName != info.Name() {
oldPath := filepath.Join(dir, info.Name())
newPath := filepath.Join(dir, newName)
os.Rename(oldPath, newPath)
fmt.Printf("重命名:%s -> %s\n", info.Name(), newName)
}
}
return nil
})
if err != nil {
fmt.Println("出错啦:", err)
}
}
// 正则提取集数和成语名
func renameVideo(name string) string {
re := regexp.MustCompile(`第?(\d+)集?[-_\s]*([\p{Han}]+)`)
match := re.FindStringSubmatch(name)
if len(match) < 3 {
return name
}
num, _ := strconv.Atoi(match[1])
newName := fmt.Sprintf("%03d_%s.mp4", num, match[2])
// 清理空格和括号残留
newName = strings.ReplaceAll(newName, " ", "")
newName = strings.ReplaceAll(newName, "(", "")
newName = strings.ReplaceAll(newName, ")", "")
return newName
}
这段代码跑一下,目录里的文件名立马整整齐齐,你看,正则表达式在Go里用起来也挺顺,\p{Han}匹配汉字,\d+抓集数,完事儿。
第二步:生成一个“365成语故事视频全集”的HTML索引页
光有文件名还不够,孩子得能点开看啊,我的想法是:自动扫描目录,生成一个index.html,里面把365个成语按集数排好,每一条链接指向对应的视频文件,这样在局域网里,用手机或平板浏览器就能直接看,不用装任何App。
Go的标准库net/http和html/template正好能搞定。
// 定义一个结构体存视频信息
type Video struct {
Num int
Name string
FileName string
}
func generateIndex(dir string) {
files, _ := os.ReadDir(dir)
var videos []Video
for _, f := range files {
if strings.HasSuffix(f.Name(), ".mp4") {
// 解析“001_画蛇添足.mp4”
parts := strings.SplitN(f.Name(), "_", 2)
if len(parts) == 2 {
num, _ := strconv.Atoi(parts[0])
name := strings.TrimSuffix(parts[1], ".mp4")
videos = append(videos, Video{Num: num, Name: name, FileName: f.Name()})
}
}
}
// 按集数排序
sort.Slice(videos, func(i, j int) bool { return videos[i].Num < videos[j].Num })
// 用模板生成HTML
tmpl := `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>365成语故事视频全集</title>
<style>
body { font-family: sans-serif; max-width: 800px; margin: auto; padding: 20px; background: #f7f3e9; }
h1 { color: #4a3b32; }
ul { list-style: none; padding-left: 0; }
li { padding: 8px; border-bottom: 1px dashed #c4b5a0; }
a { text-decoration: none; color: #6b4f3a; font-weight: bold; }
a:hover { color: #a0522d; }
.num { display: inline-block; width: 50px; color: #999; }
</style>
</head>
<body>
<h1>📚 365成语故事视频全集</h1>
<p>一共 <strong>{{len .}}</strong> 集,点击即可播放。</p>
<ul>
{{range .}}
<li><span class="num">{{printf "%03d" .Num}}</span><a href="{{.FileName}}" target="_blank">{{.Name}}</a></li>
{{end}}
</ul>
</body>
</html>`
t, _ := template.New("index").Parse(tmpl)
outFile, _ := os.Create(filepath.Join(dir, "index.html"))
defer outFile.Close()
t.Execute(outFile, videos)
}
这模板里我加了一点点样式,背景色改成了米黄色,看起来像旧书页用了个书本emoji,孩子看了不排斥,每一条视频前面显示集数,后面是成语名,点击直接新标签打开播放——简单粗暴又实用。
第三步:起个本地服务,手机直接看
文件整理好了,索引页也生成了,最后一步就是把它跑起来,用Go起个静态文件服务,就几行代码:
func main() {
addr := ":8080"
fmt.Printf("成语故事服务已启动,访问 http://localhost:%s\n", addr)
// 这目录就是视频存放的地方
http.Handle("/", http.FileServer(http.Dir("./365成语故事视频全集")))
log.Fatal(http.ListenAndServe(addr, nil))
}
跑起来之后,在手机上输入电脑的IP地址加端口,比如http://192.168.1.5:8080,就能看到那个索引页了,我特意在模板里加了target="_blank",这样在平板上点开视频,会新开一个页签播放,看完关掉就行,不会迷路。
365成语故事视频全集”这玩意儿本身,说两句
你可能会问,这365个成语故事,到底值不值得给孩子看?我翻过几集,质量参差不齐——有些是动画做的挺精美,发音也标准;有些就是PPT式的翻页配旁白,胜在内容完整。但关键是,成语这东西,它是中文的根,孩子听“画蛇添足”知道是多余,听“自相矛盾”明白逻辑漏洞,这比刷一百个短视频强,而且这套视频每集就两三分钟,正好是孩子注意力的上限。
我儿子现在每天自己打开那个页面,按集数看,看完还会跟我讲“爸爸,今天看了‘守株待兔’,那个农夫好傻”,我觉得这就够了。
留个尾巴
哦对了,如果你家的《365成语故事视频全集》文件命名不是“第X集-成语名”这种格式,比如有些是“成语故事001 画蛇添足.flv”,那你的正则表达式得改改,我上面那个renameVideo函数里,正则是第?(\d+)集?[-_\s]*([\p{Han}]+),它能匹配“第1集-画蛇添足”也能匹配“001_画蛇添足”,但匹配不了“成语故事001画蛇添足”,这活儿你得自己调调,或者你把文件名发我,我帮你看看——算了,还是自己琢磨有意思。
如果你视频文件不是.mp4是.mkv或者.avi,把代码里所有.mp4后缀换成你的就行,Go处理字符串和文件这块,真的挺省心。
写这文章的时候我旁边那杯茶都凉了,脑子也有点乱,但代码是一行行跑过的,能用,你要是家里也有这么一套视频,不如试试,顺便还能练练Go——反正比我当年用Java写文件重命名快多了。
