Using Powershell to play MP3 Audiobooks on Windows Phone

Re-post from here


So about a year ago I changed my phone to a Windows mobile 7. Overall I’m really happy with it. Without setting the world alight with evangelistic wars, I think that if the Metro interface had come before the iPhone arrived then it’s likely it would be the dominant UI.

Anyway, one major problem I had arrived when it came to playing audiobooks. The issue was that I had three challenges when playing on the windows phone.

a) For space considerations, I wanted “read” chapters to be removed from the phone automatically

b) Some books have hundreds of chapters, but some have 12 chapters each >1hr in length. It was almost impossible to pick up where you left off. Therefore I needed to use the podcast “resume” functionality in Zune

c) This led to problem #3 – when I converted the “genre” using MP3Tagedit to podcast, they would frequently end up in a jumbled play-order depending on their date, so I needed to then ensure that Chapter1 had an earlier timestamp than chapter 2 etc. to force the right order in WP7. I could eventually get what I wanted but it was very painful and involved a bunch of manual steps as well as using BulkEditor and MP3Tagedit.

I found part of the answer in an excellent post over here, where it referenced TAGLIB# . So I launched powershell for the first time and wrote the script below.

Now, if you target it at a folder such as…

William Shakespeare/

Merchant of Venice/

Chapter1.mp3 ……



It will loop through the subdirectories… renaming the files in sequence… setting the appropriate MP3 tag entries… Author = William Shakespeare/Album = BookDirectoryName/Chapter = Title.. and setting timestamp to force Zune to recognise chapter 1 as being before chapter 2..

So, here’s the code I used:

Function Zune
		[Parameter(Position=0, Mandatory=$True)]



	$OriginDir = Get-Location

	#========Does the libary exist and contain books?=============================================

	if ((Test-Path -Path $Library) -eq $false) {
		write-output "$Library Does Not Exist"

	$Books = Get-ChildItem $Library | where {$_.psiscontainer}
	if (!$books) {
		Write-Output "$Library Contains no books"

	$librarylocation = Get-Item $Library

	fault Parameters===========================================================
	if (!$Genre)
		Write-Host "Genre is blank, using Default $Genre" -foregroundcolor DarkGreen
		Write-Output "Genre is " + $Genre

	#========Load Assemblies======================================================================
	$TaglibLocation = (Resolve-path ($ProfileDir + "taglibtaglib-sharp.dll"))
	Add-Type -Path ($TaglibLocation)
	Write-output "Taglib Loaded Successfully"

	#========Set up Recursive Subdirectories======================================================
	Write-Output "Processing the Library $Library"
	$NumberBooks = $books | Measure-Object | Select-Object -ExpandProperty Count
	Write-Output "Total Number of Runs is $Numberbooks"

	if ($NumberBooks -gt 0)
		Set-Location $Librarylocation
		foreach ($book in $Books)
			Write-Host "==================================================" -foregroundcolor Blue
			Write-Output "$("Processing the Book ")$($$(" in ")$($librarylocation)"
			$Chapters = Get-ChildItem $ *.mp3 | Sort-Object Name
			$NumberChapters = $Chapters | Measure-Object | Select-Object -ExpandProperty Count

			if ($NumberChapters -gt 0)

				if ($NumberChapters -le 100)
					$pad = 2
				elseif ($NumberChapters -le 255)
					$pad = 3
				elseif ($NumberChapters -ge 256)
					Write-Output "$("Too Many chapters in the book :")$($"

				Write-Output "$("Processing ")$($NumberChapters)$(" Chapters")"

				#========Set up Recursive Subdirectories==========================================
				set-location $book.fullname
				foreach ($chapter in $Chapters)
					$title = "{0:D$pad}" -f ($i) +"$(" of $NumberChapters- ")$($"
					$Filename = $title + '.mp3'
					$media = [TagLib.File]::Create($chapter.Fullname)
					$media.Tag.Title = $title
					$media.Tag.Performers = "Narrator"
					$media.Tag.AlbumArtists = (get-culture).Textinfo.Totitlecase($Library.tolower())
					$media.Tag.Composers = "Composer"
					$media.Tag.Album = $
					$media.Tag.Comment = $chapter.Name
					$media.Tag.Genres = $Genre

					if (!$media.Tag.Year) {$media.tag.year = (Get-date).Year}
					$media.Tag.Track = $i
					$media.Tag.Artists = (get-culture).Textinfo.Totitlecase($Library.tolower())


					$chapter.Creationtime = (Get-Date).date.addminutes($i)
					$chapter.LastWriteTime = (Get-Date).date.addminutes($i)
					#$chapter.LastAccessTime = (Get-Date).date.addminutes($i)
					$chapter.LastWriteTimeUTC = (Get-Date).date.addminutes($i)
					$chapter.CreationtimeUTC = (Get-Date).date.addminutes($i)
					#$chapter.LastAccessTimeUTC = (Get-Date).date.addminutes($i)
					Write-Output "$("Renaming ")$($$(" to ")$($Filename)"
					Rename-Item $chapter.fullname $filename

				Write-Output "$("No Chapters inside the book :")$($book)"

		Set-Location $Librarylocation

		#========================     end of loop on books =============================================
		Write-Output "$($"No Books inside the Library "$($Library))"

	#========================     end of function     ==================================================
	Set-Location $OriginDir

Export-ModuleMember -Function Zune