当前位置:首页 > 体育 > 正文

用Go语言给孩子搭个365成语故事视频全集小工具?这活儿我干过

  • 体育
  • 2026-08-05 05:59:00
  • 11
摘要: 昨儿晚上我家那口子又念叨,说孩子天天抱着平板看动画片,不如看点有营养的——得,又是“365成语故事视频全集”这茬儿,我一边答应着...

昨儿晚上我家那口子又念叨,说孩子天天抱着平板看动画片,不如看点有营养的——得,又是“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/httphtml/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写文件重命名快多了。

用Go语言给孩子搭个365成语故事视频全集小工具?这活儿我干过