Here's something I threw together the other day to help me organize my ripped audio books. I have several audio books (Harry Potter, LOTR, Dresden Files, etc) that I've been ripping to file so that I could gather an entire 10-20 CD set onto a single disc for easy listening while driving without needing to switch discs. I like to use WMA files for easy ripping (via Media Player) and the small footprint.
I've found, much to my chagrin, that the information retrieved online for these books (via CDDB, FreeDB, or All Music Guide (which WMP uses)) is unreliable, frequently contains typos and misspellings, and is extremely inconsistent with respect to formatting and convention.
I found that when I inserted a CD I would spend a good amount of time entering the book name, the genre, the year it was recorded, the author, and the performer, and I'd take the time to rename the tracks. After a handful of CDs this was almost unbearable and extremely tedious.
I therefore set out to write a script that would do this, updating all of the ID3 tags after the fact. The only thing I would need to concern myself with was that the book name (I like the form Book Name - Disc XX) was correct. This script belows makes a few assumptions about the folder and file names:
- each folder contains a single disk and that they are named according to the pattern "Book Name - Disc XX"
- all books will be collected into a single folder with the name pattern "Book Set - Book Name"
For example, I ripped a book by Jim Butcher named Small Favor. Each disc went into a folder named "Small Favor - Disc 01", "Small Favor - Disc 02", etc. I would then collect all the ripped files into a single directory named "Dresden Files - Book 10 - Small Favor". This way, when all was said and done, I'd have all the books in order and grouped.
I decided to use PowerShell as the language of preference for automating this procedure. Not only does it provide a very powerful scripting environment, but I can also leverage the .NET Framework (which I love dearly). As such, I was able to take advantage of TagLib#'s ability to edit the tags within the files. This script assumes that the taglib-sharp.dll is in the same directory as the .ps1 script file.
The following PowerShell scripts performs all the collecting, enumerating, and tagging of my files. Feel free to adapt it and tweak it according to your own preferences. If you have suggestions, I'd welcome them. Like I said, I threw it together in a very short time so it's probably weak in many regards but seems to get the job done.
Taking my example above, my command line would be:
.\collectaudiobook "Small Favor" "Dresden Files - Book 10" "Jim Butcher" "James Marsters" 2008
Now I don't need to worry about what information was loaded from the CDDB-esque service, the script updates it all after-the-fact. :)
CollectAudioBook.ps1
$a = $args.length
if ( $a -lt 2 ) {
write @"
USAGE:
`t.\CollectAudioBook.ps1 titlePrefix targetFolderPrefix [author] [artist] [year]
REQUIRED PARAMETERS:
titlePrefix
`tSpecifies the subfolders to process as a single book.
`t(e.g., 'Small Favor' would locate 'Small Favor - Disc 01', 'Small Favor - Disc 02', etc)
`tThe folders are processed in order by name, assuming that to be the proper sequencing of the resulting files.
targetFolderPrefix
`tSpecifies the target folder to which all tracks are collected. If this
`tfolder doesn't exist, it is created.
`tNOTE: The folder's full name will be comprised of the targetFolderPrefix, a hyphen, and the titlePrefix.
`t(e.g., a titlePrefix of 'Small Favor' and a targetFolderPrefix of 'Dresden Files - Book 10' becomes
`tDresden Files - Book 10 - Small Favor)
author
`tIdentifies the author of the book.
artist
`tIdentifies the name of the performer.
year
`tIdentifies the year of the recording.
"@
exit
}
$bookName = $args[0]
$bookSet = $args[1] + ' - ' + $bookName
$author = $args[2]
$artist = $args[3]
$year = $args[4]
$target = '.\' + $bookSet
$partNum = 0
# load taglib-sharp.dll which allows for the manipulation on the media tags in the files
$asm = [Reflection.Assembly]::LoadFrom((Resolve-Path ".\taglib-sharp.dll"))
# create the target directory
$dir = New-Item -path "$target" -type directory -force
# enumerate all files in each folder that start with the prefix, copying and renaming each file
foreach ( $folder in ( Get-ChildItem .\$bookName* | Where-Object { $_.Mode.StartsWith('d') } | Sort Name ) ) {
foreach ( $file in ( Get-ChildItem $folder | Sort Name ) ) {
++$partNum
$targetPrefix = 'Part ' + $partNum.ToString("00")
$targetFileName = $targetPrefix + '.wma'
write "Copying $file`t-->`t$targetFileName"
Copy-Item $folder\$file $target\$targetFileName
# update the media information in the file
$media = [TagLib.File]::Create((Resolve-Path "$target\$targetFileName"))
$media.Tag.Title = $bookName + ' - ' + $targetPrefix
if ( $author -ne $null ) { $media.Tag.AlbumArtists = $author }
if ( $artist -ne $null ) { $media.Tag.Performers = $artist }
$media.Tag.Genres = { Audio Book }
if ( $year -ne $null ) { $media.Tag.Year = $year }
$media.Save()
}
}