mp4chaps 的 mp3 文件的时间长度

Time length of mp3 files for mp4chaps

我一直在努力使用一些 bash 代码来根据 mp3 文件的时间长度生成一个 mp4chaps.chapters.txt 文件,这样当我将它转换为有声读物 (m4b) 时,我可以重新添加章节信息

我想我已经解决了,但我很好奇这是否可以更优雅地完成?

我的poc代码(假设你运行这个脚本所在的文件夹里有mp3文件):

#!/usr/bin/env bash
echo "00:00:00.000 Chapter 1" 
i=2
total_seconds=0
total_millis=0
for mp3 in *.mp3; do
  duration=$(ffprobe -v quiet -print_format json -show_format "${mp3}" | jq ".format.duration"|sed 's/"//g')
  millisecs="$(echo $duration | awk -F'.' '{print }')"
  millisecs="${millisecs#"${millisecs%%[!0]*}"}"
  total_millis=$((total_millis + millisecs))
  secs=$((total_millis / 1000000))
  total_millis=$((total_millis - (secs * 1000000)))
  total_seconds=$((total_seconds + $(echo $duration | awk -F'.' '{print }') + secs))
  hour=$((total_seconds / (60 * 60)))
  minutes=$(((total_seconds - (hour * 60 * 60)) / 60))
  seconds=$((total_seconds - (hour * 60 * 60) - (minutes * 60)))
  hour=$(printf "%02d" $hour)
  minutes=$(printf "%02d" $minutes)
  seconds=$(printf "%02d" $seconds)
  echo "$hour:$minutes:$seconds.${millisecs:0:3} Chapter $i"
  i=$((i + 1))
done

一个mp4chapts.chapters.txt文件的格式是这样的:

00:00:00.000 Chapter 1
00:11:46.612 Chapter 2
00:22:55.525 Chapter 3
00:41:22.670 Chapter 4
01:09:17.337 Chapter 5

ffprobe json格式为:

{
    "format": {
        "filename": "Book with chapter 01.mp3",
        "nb_streams": 1,
        "nb_programs": 0,
        "format_name": "mp3",
        "format_long_name": "MP2/3 (MPEG audio layer 2/3)",
        "start_time": "0.025057",
        "duration": "706.612245",
        "size": "5657329",
        "bit_rate": "64050",
        "probe_score": 51,
        "tags": {
            "title": "a good book 01",
            "artist": "The Author",
            "album": "fantastic album information",
            "track": "01",
            "publisher": "Good Media, Inc",
            "genre": "Fiction",
            "comment": "Read by ...",
            "copyright": "2019",
            "date": "2021"
        }
    }
}

我使用这个 json 的持续时间。

请您尝试以下操作:

echo "00:00:00.000 Chapter 1"
i=2
total_millis=0
for mp3 in *.mp3; do
  duration=$(ffprobe -v quiet -show_entries format=duration "${mp3}" | sed -n 's/duration=//p')
  millisecs=$((${duration%.*} * 1000 + 10#${duration#*.} / 1000))
  ((total_millis += millisecs))
  hour=$((total_millis / 3600 / 1000))
  mins=$(((total_millis - hour*3600*1000) / 60 / 1000))
  secs=$(((total_millis - hour*3600*1000 - mins*60*1000) / 1000))
  millis=$((total_millis - hour*3600*1000 - mins*60*1000 - secs*1000))
  printf "%02d:%02d:%02d.%03d Chapter %d\n" "$hour" "$mins" "$secs" "$millis" "$i"
  ((i++))
done

恐怕还是不够优雅。我统一了要累积的变量 进入 total_millis 的时间量使代码更短 比原来的。顺便说一句,你在 echo 中的 millisecs 值 行可能不正确。直接从当前章节计算 不反映 total_millis.

的值

[备选]

如果你的date命令支持-d选项,这里有一个作弊方法:

echo "00:00:00.000 Chapter 1"
i=2
total_secs=0
for mp3 in *.mp3; do
  duration=$(ffprobe -v quiet -show_entries format=duration "${mp3}" | sed -n 's/duration=//p')
  total_secs=$(echo "$total_secs + $duration" | bc)
  day=$(date -d "@$total_secs" -u +%d)
  hour=$(( 10#$(date -d "@$total_secs" -u +%H) + (10#$day - 1) * 24 ))
  printf "%02d:%s Chapter %d\n" "$hour" "$(date -d "@$total_secs" -u +%M:%S.%3N)" "$((i++))"
done

date 命令的行为在很大程度上取决于平台,上面的解决方案不可移植。