List audiobooks and/or music based on directories
Alec Jacobson
August 11, 2009
This began as a script to count up the number of books and authors in my audiobook collection. The directories looked like this:
audiobooks/
ernest hemingway/
for whom the bell tolls/
the sun also rises/
f scott fitzgerald/
tender is the night/
[and so forth]
Each author had a folder which held subfolders for each book, in turn those book folders held the actual mp3 files (or even further subfolders for each CD).
Using ls
I managed to extract a count of the author folders and a count of the internal, book folders. Here's that simple bash script:
#!/bin/bash
# Usage
plain=`ls -1 "$1"/*`
#guarantee a new line at the end of the file
plain="$plain
"
NUMTITLES=`echo "$plain" | grep -iv ":$" | grep -vc ^$`
NUMAUTHORS=`echo "$plain" | grep -c ":$"`
echo "There are $NUMTITLES book titles and $NUMAUTHORS authors."
If you save that script in a file called count.sh
, then run it on the command line with ./count.sh audiobooks/
(replacing "audiobooks/" with the path to your top level folder, the one holding the author folders).
So then I thought why not transform this to also print out a nice readable list of my books. The command ls -1 *
already makes a nice list. Notice that the -1
tells ls
to only look one level deep recursively, and *
ignores things like .
and ..
from being searched. So I simply tacked on
echo "$plain" > "booklist.txt"
to the end of the code above.
Plain text is great for quick searching and viewing on a terminal, but occasionally I wanted to show my list to friends where a slick, clean html page would be more appropriate. So here is a full fledged command line app with argument requirements and all. Save it in a file called list.sh
:
#!/bin/sh
USAGE="Usage: list [filename] [directory]
If filename ends with .html then output will be html,
else output will be plain text."
if test -z "$1" || test -z "$2"
then
echo "$USAGE"
exit 1
fi
if [ ! -d $2 ]; then
echo "list: $2 is not a directory"
echo "$USAGE"
exit 1
fi
dir=$2
plain=`ls -1 "$dir"/*`
#guarantee a new line at the end of the file
plain="$plain
"
NUMTITLES=`echo "$plain" | grep -iv ":$" | grep -vc ^$`
NUMAUTHORS=`echo "$plain" | grep -c ":$"`
echo "There are $NUMTITLES book titles and $NUMAUTHORS authors."
if [[ "$1" != *.html ]]; then
echo "$plain" > $1
else
HNAME=$1
html=`echo "$plain" \
| sed "s/\(.*\)\([^:]\)$/ \1\2<\/br>/" \
| sed "s/^\s*$/ <\/div>/" \
| sed "s/.*\/\(.*\):$/ <h3>\1<\/h3> <div class='books'>/"`
html="<html>
<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>$NUMTITLES book titles and $NUMAUTHORS authors</h2>
$html
</body>
</html>"
echo "$pre $html $post" > $1
fi
Then on the command line run this with two arguments: the output file and the path to the directory containing the author folders. Run using: ./list.sh output.html audiobooks/
to produce an html list in output.html or ./list.sh output.txt audiobooks/
to throw the ls -1 *
output into a plain text file.
Check out the html listing of my audiobooks folder.
Note: Change all the book/author stuff to whatever you're listing or some generic terms maybe.
Update: sed
stalls if you give it too much, so this script fails on large directories. Check out the new ruby version which works well on large directories.