Posts Tagged ‘audiobook’

Split a long mp3 audio file into 3 min files

Wednesday, July 29th, 2015

After some frustration trying to get mp3splt to work, I caved in and wrote a script to split apart a large audio file into many 3min chunks. Save this in mp3split.sh:

#!/bin/bash
big="$1"
duration_stamp=$(ffmpeg -i "$big" 2>&1 | grep Duration | sed 's/^.*Duration: *\([^ ,]*\),.*/\1/g')
title=$(ffmpeg -i "$big" 2>&1  | grep "title *:" | sed 's/^.*title *: *\(.*\)/\1/g')
# get minutes as a raw integer number (rounded up)
prefix=$(basename "$big" .mp3)
echo $duration_stamp
mins=$(echo "$duration_stamp" | sed 's/\([0-9]*\):\([0-9]*\):\([0-9]*\)\.\([0-9]*\)/\1*60+\2+\3\/60+\4\/60\/100/g' | bc -l | python -c "import math; print int(math.ceil(float(raw_input())))")
ss="0"
count="1"
total_count=$(echo "$mins/3+1" | bc)
while [ "$ss" -lt "$mins" ]
do
  zcount=$(printf "%05d" $count)
  ss_hours=$(echo "$ss/60" | bc)
  ss_mins=$(echo "$ss%60" | bc)
  ss_stamp=$(printf "%02d:%02d:00" $ss_hours $ss_mins)
  ffmpeg -i "$big" -acodec copy -t 00:03:00 -ss $ss_stamp -metadata track="$count/$total_count" -metadata title="$title $zcount" "$prefix-$zcount.mp3" 
  ss=$[$ss+3]
  count=$[$count+1]
done

The execute mp3split.sh my-long-file.mp3. This will output a sequence of files:

my-long-file-00001.mp3
my-long-file-00002.mp3
my-long-file-00003.mp3
my-long-file-00004.mp3
...

Each will retain the meta data from the original file except the file number will be appended to the track name and the track number will be set accordingly (i.e. this will work well for splitting enormous audiobook files into file lists that play in the correct sequence on an iphone).

Note: mp3splt really seems like the right tool for this. It supposedly has fancy features like silence detection and presumably won’t reload the file for each new split.

List audiobooks and/or music based on directories: Ruby Version

Thursday, November 5th, 2009

I previously posted a bash script to count and print plain text and html listings of a directory: intended for displaying audiobook and music libraries. I recently tried to use the bash script on a large directory and it stalled because sed can’t handle large input. Here’s a ruby version that does the same thing:


#!/usr/bin/ruby -w
usage = "Usage: list [filename] [directory] 
If filename ends with .html then output will be html,
else output will be plain text."
if not ARGV[0] or not ARGV[1]
  puts usage
elsif not File.directory? ARGV[1]
  puts "list: #{ARGV[1]} is not a directory"
  puts usage
else
  dir = ARGV[1]
  # should be quoted?
  plain = (`ls -1 "#{dir}"/*`+"\n")
  if(ARGV[0] =~ /.html$/i)
    plain = plain.split("\n")
    author_count = plain.find_all{|line| line=~/:$/}.length
    title_count = plain.find_all{|line| line=~/[^:]$/}.length
    body = plain.collect do |line|
      line.gsub(
        /(.*)([^:])$/,'      \1\2</br>').gsub(
        /^\s*$/,'    </div>').gsub(
        /.*\/(.*):$/,'    <h3>\1</h3>'+"\n"+'    <div class="books">')
    end
    output = "<html>
  <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/> 
  <head> 
    <style type='text/css'>
      body {
        font : 10pt verdana;
        background: white;
        width: 95%
      }
      h2 {
        margin: 15px 0px 5px 0px;
      }
      h3 {
        margin: 15px 0px 5px 0px;
      }
      .books {
        border: 1px solid #dddddd;
        padding: 5px 5px 5px 10px;
        background: #eeeeff;
      }
    </style>
  </head>
  <body>
    <h2>#{title_count} titles and #{author_count} authors</h2>
  #{body.join("\n")}</div>
  </body> 
</html>"
  else
    output = plain;
  end
  File.open(ARGV[0], 'w') {|f| f.write(output) }
end