Regular-Expression

從文件名中提取時間戳以拆分 mp3

  • January 3, 2022

我在一個文件夾中有一堆 mp3 文件。它們是從盒式磁帶錄製的,需要分離出各個軌道。這是文件名之一:

Gobbolino the Witch's Cat, 10:52 The Hare & Tortoise, 14:52 The Shoe Tree, 24:22 The Emperors New Clothes, 34:11 The Red Nightcaps, 37:07 Aldo in Arcadia (1), 40:37 The Forest Troll.mp3

您可以看到它在文件名中有時間戳,表示每個曲目的開始。第一個曲目沒有時間戳,因為它總是從 00:00 開始。最後一首曲目應該總是到 mp3 的末尾。不知何故,我想提取這些時間戳以創建單獨的文件。

如果上面的文件被正確分割,輸出將是:

Gobbolino the Witch's Cat.mp3
The Hare & Tortoise.mp3
The Shoe Tree.mp3
The Emperors New Clothes.mp3
The Red Nightcaps.mp3
Aldo in Arcadia (1).mp3
The Forest Troll.mp3

我知道如何循環文件,以及如何使用 ffmpeg 剪切文件,但我不知道如何從文件名中提取時間戳和跟踪名稱。我正在使用 zsh,這是我目前的程式碼:

for file in *; do
 if [[ -f "$file" ]]; then
   # extract timestamps and loop thru, for each timestamped section
   ffmpeg -ss TIMESTAMP_START -to TIMESTAMP_END -I "$file" -acodec copy TRACK_NAME.mp3
 fi
done

更新

我對這個問題的規範已經改變。文件名如下所示:

Tape 1 - Gobbolino the Witch's Cat, 11-06 The Hare & Tortoise, 14-25 The Shoe Tree, 24-06 The Emperors New Clothes, 34-27 The Red Nightcaps, 37-29 Aldo in Arcadia (1), 40-40 The Forest Troll.mp3

即它在開頭有一個專輯名稱,並且時間戳中有連字元而不是冒號(文件名在macOS中不能有冒號)。另外,我想在文件中插入一些 mp3 標籤,並將每張專輯的曲目放在自己的專輯文件夾中。

我的解決方案基於下面的 Gilles 之一。腳本如下所示:

setopt interactive_comments
for file in *(.); do
   extension=$file:e
   rest=$file:r
   timestamp_start=0:00
   timestamp_duration=$(ffprobe -i "$file"  -show_entries format=duration -v quiet -of csv="p=0" -sexagesimal -sexagesimal)
   timestamp_duration=${timestamp_duration%.*}
   tracknum=1
   while [[ $rest =~ ,\ *([0-9:]+-[0-9][0-9])\ * ]]; do
       track_name="$rest[1,$MBEGIN-1]"
       if [[ "$track_name" == *"Tape "* ]]; then
      albumname="${track_name%% - *}"
          track_name="${track_name#* - }"
          echo "\n\nALBUM NAME $albumname\n"
          mkdir $albumname
       fi
       rest=$rest[$MEND+1,-1]
       timestamp_end=$match[1]
       timestamp_end="${timestamp_end//-/:}"

   # echo "$timestamp_start $timestamp_end $track_name.$extension"
       ffmpeg -ss $timestamp_start -to $timestamp_end -i $file -acodec libmp3lame -ac 2 -ab 256k -ar 44100 -metadata album="$albumname" -metadata title="$track_name" -metadata track="$tracknum" $track_name.$extension
       mv $track_name.$extension $albumname
       timestamp_start=$timestamp_end
       tracknum=$((tracknum+1))
       last_track_name="$rest:r"
   done
   if [[ -n $timestamp_end ]]; then
       # echo "$timestamp_start $timestamp_duration $last_track_name.$extension"
       ffmpeg -ss $timestamp_start -to $timestamp_duration -i $file -acodec libmp3lame -ac 2 -ab 256k -ar 44100 -metadata album="$albumname" -metadata title="$last_track_name" -metadata track="$tracknum" $last_track_name.$extension
       mv $last_track_name.$extension $albumname
   fi
done

在文件名上使用循環來匹配軌道分隔符,使用正則表達式匹配=~ 條件表達式運算符。正則表達式,\ *([0-9:]+:[0-9][0-9])\ *匹配一個逗號,後跟一個帶有可選空格的時間戳。

$file:e並通過歷史修飾符$file:r提取文件副檔名。

不要循環遍歷所有文件然後只匹配正常文件,而是使用glob 限定符來匹配正常文件。

for file in *(.); do
   extension=$file:e
   rest=$file:r
   timestamp_start=0:00
   timestamp_end=
   while [[ $rest =~ ,\ *([0-9:]+:[0-9][0-9])\ * ]]; do
       track_name=$rest[1,$MBEGIN-1]
       rest=$rest[$MEND+1,-1]
       timestamp_end=$match[1]
       ffmpeg -ss $timestamp_start -to $timestamp_end -I $file -acodec copy $track_name.$extension
       timestamp_start=$timestamp_end
   done
   if [[ -n $timestamp_end ]]; then
       ffmpeg -ss $timestamp_end -I $file -acodec copy $rest.$extension
   else
       : # If you want special processing for single-track files, it goes here.
   fi
done

引用自:https://unix.stackexchange.com/questions/684588