Support for audiobooks

Seriously the one thing I want in plex that they don’t already have.

I’ve been brainstorming on this for a while and think I’ve found a very good work around. I’m going to make a new “TV Shows” library and call it “Audio Books”. I’m going to then treat every book as it’s own TV show and every chapter as it’s own TV episode. I’m going to then use iMovie or an ffmpeg script to convert every audio file into an h265 .mv4 file with the video portion being a static image of the books cover. If I get ready ambitious I might even try to automate converting the book audio into subtitles. The end result should be that my audio book collection has the same behavior as my TV shows collection. Meaning; currently playing, saved position, next up, etc will all just work.

Good idea except 1) there is no agent to get the metadata for such a library so you would have to manually input it all and 2) not practical when you have over 5,000 audio books like I do.

1 Like

you’re taking a huge gamble there with your time and energy. what are the chances plex changes settings in video or movie libraries again in the next 5yrs and *ucks up your own setup? its always tedious work for work arounds but honestly, plex devs should hunker down and get a seperate audio library for audiobooks done and complete. period. as it is, ive created my own work around for music videos how i like it but deep down i feel eventually plex will likely break the work flow that ive created for myself. at some point it becomes just stupid on their part for not addressing these bandaids by implementing proper tools for these additional media categories. we should not need bandaids nor workarounds. and ive seen my fair share of disappointed individuals whom already had put in so much energy into the metadata in their audiobooks or music libraries only for plex to ignore half of it (myself included), causing these people frustration when they become shocked that metadata is missing or wont be read by plex because it just wont. dumb.

I’ve got automation to do a lot of what you’re describing. I’m at about 100 audiobooks right now and it required very little work. The only thing you need to do is name the files correctly, but you need to do that in Plex anyway.

The demand for this is so high, the requests have been coming in for so long, and the majority of the requests are from plex pass users. The code needed for them to offer at least the very basic library support is already written and likely only needs a few things added. They went out of their way to make a whole separate music app and didn’t bother to gear it to work with audiobooks at release. This shows me that not only do they not give a ■■■■ about what their customers want, but I see this response (or lack of) as a big ■■■■ you.

Good points. I think mixing the audio book into a movie with chapter points instead of tv episodes would be more resilient. And I think I’ll be able to add the movies as home video entries into themoviedb.org so that the plex agent will automatically pick up the metadata.

I have a ■■■■ of my own for Plex to. Meaning canceling the subscription.

I disagree. It’s a gamble to wait for plex to provide complete support for every permutation of content you’re interested in. Instead, by creating some (very) basic tools and managing your own personalized solution you’ll spend your time enjoying your content instead of waiting and feeling left behind.

Pandas, what was your solution?

As you mentioned the approach is to home your audiobooks in plex library of type “tv show” (which, IMO, is an unfortunate label that throws people off. Most of my content in these libraries are not in fact TV Shows. And as you can see here, some are not even VIDEO). This allows you to leverage all the functionality of this library type.

You do this by converting a series of audio clips into MP4 (or M4V) files. The audio track is typically in aac format. The container should not contain a video track. There are lots of tools for generating this. I use ffmpeg but if you need a GUI I recommend staxrip.

As you mention you can also include a video track constructed from the artwork. I think that’s a great idea. I don’t do this because I play my audiobooks through my stereo but it’s a brilliant idea.

Here’s the key:

Deploy the files in the standard “tv show” naming format: TITLE - EPISODE_ID - DESCRIPTION.mp4

Then:

Run a python plex API script that reads the plex database, extracts DESCRIPTION from the filename, and updates the episode title in the Plex UI. The script can be run from any host on the same subnet as the plex server host.

The only manual thing you need to do is to grab artwork from google images and put it in the directory as cover.jpg, background.jpg, etc

Script follows

# Updates multipart/series video metadata in Plex
# Sets episode title based on string embedded in filename
##############################################################

import re
import sys

TARGET_SERIES = "ZZZ"

TARGET_LIBRARY = "ZZZ"

if len(sys.argv) > 1:
	TARGET_SERIES=sys.argv[1]

USERNAME="ZZZ"
PASSWORD=ZZZ"
SERVERNAME="ZZZ"

from plexapi.myplex import MyPlexAccount
account = MyPlexAccount(USERNAME, PASSWORD)
# returns a PlexServer instance
plex = account.resource(SERVERNAME).connect()  

episodes = plex.library.section(TARGET_LIBRARY).get(TARGET_SERIES).episodes()
print("Found %d episodes for: %s" % (len(episodes), TARGET_SERIES))
match_str = 's[0-9][0-9]e[0-9][0-9].*$'

# Extract episode name (AKA episode title) from episode video filename on disk
# Input  : Episode filename 
# Output : Episode name
# Format : SERIES_TITLE - s99e99 EPISODE_TITLE.mp4
# Example:
# Input  : Leave it to Beaver - s01e01 Junior loses the screwdriver.mp4
# Output : Junior loses the screwdriver

for episode in episodes:
	# print(episode.title)
	filename = episode.media[0].parts[0].file.split('\\')[-1]
	print("\nProcessing: %s" % (filename))
	# Parse keying on season/episode string form: s99e99
	tmp = re.findall(match_str, filename)

	# Generate episode title
	new_episode_title = None
	try:
		words = tmp[0].split(" ")
		# Get rid of "s99e99" (first word)
		words = words[1:]
		# May contain "-" after s/e 
		if words[0] == "-":
			words = words[1:]
		# Remove file suffix: mp4, mov, etc
		words[-1] = words[-1].split(".")[0:-1][0]

		new_episode_title = " ".join(words)
		new_episode_title = new_episode_title.replace("_",":")
	except Exception as e:
		print("Could not parse filename of episode: %s" % (filename))
		continue

	# Update episode metadata in Plex
	print("Updating title: %s" % (new_episode_title))
	try:
		dict_param = {"title.value": new_episode_title}
		episode.edit(**dict_param)
	except Exception as e:
		print("Failed to update Plex error: %s" % (e))


I don’t think making video files from your audiobooks is a good solution. For one thing, you can’t turn off your screen. Once you do, the audio will pause. That means the battery on your device will plummet by having the screen on all the time, given how long audiobooks are.

My first observation would be, it’s important to distinguish between something that is not a good solution generally, and one that is not a good solution just for you specifically. Users have a variety of needs and use cases, and your statement, even if it were true, would apply only to mobile.

Second observation: I use iphone and turning off the screen while listening does not interfere with playback.

Honestly, I was somewhat satisfied with the solution being to use a third-party app.

But then 1) Prologue is only on iOS (and I use Android); 2) Chronicle is abandonware; and 3) Bookcamp is non-existent, with no (even open beta) release date in sight.

So my solution, as it has been for a few years now, is to use Emby to manage and sync my audiobook library; and use Sirin Audiobook Player to play them locally on my device.

Okay, so here is the rough beginnings of my bash script that uses ffmpeg to convert a folder of audio files into a movie with embedded chapters, title, and cover. It also pads the end of the movie with 15% silence so that Plex will not automatically mark the audio book as read before you finish listening to it. Format matters here in the same way that it matters for Plex. Everything before a dash is considered the book’s title and everything after the dash but before the file extension is considered the chapter name. Naming all the files as “Book Title - Chapter XX partXX.ext” should work provide good results. Supported file extensions are: .aa, .aac, .aax, .flac, .m4a, .mp3, .ogg, .oga, .mogg, .wav, .wma, .webm (though I confess to have only tested this with .mp3 files so far). Also, you must provide a .jpg file in the folder named cover.jpg. Original files will not be modified other then to move them to a sub-directory named “original”.

The command is as follows if you name the script videoify.sh:

bash videoify.sh vcodec ./path/to/audiobook/directory

In testing I used:

bash videoify.sh h264_videotoolbox ./Test

Note: You can not yet have spaces in the supplied path. I will address this in the future but for now you will need to use underscores instead of spaces. Audio filenames can contain spaces which will make your title and chapter names look normal.

And here is the script:

#! /usr/bin/env bash
# set the video codec; some options include hevc_videotoolbox, h264_videotoolbox, or libx264
vcodec=$1
# set the path to the directory where the audio book files are
path=$2
# create a tmp directory if one does not exist
mkdir -p "$path/tmp/tmp"
# create a original directory if one does not exist
mkdir -p "$path/original"
# make sure all audio files are encoded the same
for extension in {aa,aac,aax,flac,m4a,mp3,ogg,oga,mogg,wav,wma,webm}; do
	for filename in $path/*.$extension; do
		if [[ $filename != *\*.$extension ]];
		then
			# set title to be the filename
			title=$filename
			# set audio name to be filename
			audioname=$filename
			# everything after the last / is considered the audio name
			audioname=${audioname##*/}
			# everything before the last . is considered the audio name
			audioname="${audioname%.*}"
			ffmpeg -i "$filename" -vn -ar 44100 -ac 2 -b:a 192k -acodec aac "$path/tmp/$audioname.aac"
			# move the file to the original directory
			mv "$filename" "$path/original/${filename##*/}"
		fi
	done	
done
# everything after the last / is considered the title
title=${title##*/}
# everything before the first - is consifered the title
title="${title%%-*}"
# replace ' with \'
title=${title//\'/\\\'}
# trim whitespace from title
title=$(echo $title | xargs)
# set the name of the video's metadata file
metadata="$path/tmp/metadata.txt"
# create a temp metadata file for the video
touch "$metadata"
# write header metadata to the video's temp metadata file
echo ";FFMETADATA1" > "$metadata"
echo "title="$title >> "$metadata"
echo "" >> "$metadata"
# initialize the chapter start time in milliseconds
start="0"
# initialize the chapter end time in milliseconds
end="0"
# initialize count
count="100000"
step="1"
for filename in $path/tmp/*.aac; do
	# get the chapter's duration from the video
	duration=`ffmpeg -i "$filename" 2>&1 | awk '$1 ~ /^Duration/' | cut -d ' ' -f 4 | sed s/,// | awk '{ split($1, A, ":"); print 3600000*A[1] + 60000*A[2] + 1000*A[3] }'`
	# set the chapter name to be the filename
	chaptername=$filename
	# everything before the last . is considered the chapter name
	chaptername="${chaptername%.*}"
	# everything after the first - is considered the chapter name
	chaptername="${chaptername#*-}"
	# trim whitespace from chapter name
	chaptername=$(echo $chaptername | xargs)
	# add the chapter's duration to the chapter's start time
	end=$(( $start + $duration ))
	# write chapter's metadata to the video's temp metadata file
	echo "[CHAPTER]" >> "$metadata"
	echo "TIMEBASE=1/1000" >> "$metadata"
	echo "START=$start" >> "$metadata"
	echo "END=$end" >> "$metadata"
	echo "title="$chaptername >> "$metadata"
	echo "" >> "$metadata"
	# set next chapter's start time to this chapter's end time
	start=$end
	mv "$filename" "$path/tmp/tmp/$count.aac"
	count=$(( $count + $step ))
done
# popuate the temp list of all the video chapters
concat=""
for filename in $path/tmp/tmp/*.aac; do
	concat="${concat}|${filename}"
done
# keep everything after the first |
concat="${concat#*|}"
# merge all the audio files together
ffmpeg -i "concat:$concat" -c copy "$path/tmp/tmp/book.aac"
# determine duration of %15 silence
duration=`ffmpeg -i "$path/tmp/tmp/book.aac" 2>&1 | awk '$1 ~ /^Duration/' | cut -d ' ' -f 4 | sed s/,// | awk '{ split($1, A, ":"); print 540*A[1] + 9*A[2] + A[3] }'`
# generate 15% silence
ffmpeg -f lavfi -i anullsrc=r=11025:cl=mono -t "$duration" -vn -ar 44100 -ac 2 -b:a 192k -acodec aac "$path/tmp/tmp/silence.aac"
# append silence to book
ffmpeg -i "concat:$path/tmp/tmp/book.aac|$path/tmp/tmp/silence.aac" -c copy "$path/tmp/tmp/paddedbook.aac"
# convert audio file to video file
ffmpeg -r 1 -loop 1 -i "$path/cover.jpg" -i "$path/tmp/tmp/paddedbook.aac" -c:a copy -r 1 -vcodec $vcodec -shortest "$path/tmp/tmp/book.mkv" -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2"
# add chapter data to video file
ffmpeg -i "$path/tmp/tmp/book.mkv" -i "$metadata" -map_metadata 1 -codec copy "$path/$title.mkv"
# uncomment next line to save audio file too
#mv "$path/tmp/tmp/paddedbook.aac" "$path/$title.aac"
# move cover.jpg to original directory
mv "$path/cover.jpg" "$path/original/cover.jpg"
# remove tmp directory
rm -rf "$path/tmp"

I have an iPhone that I use and my experience has been that the audio will stop when the screen is turned off if I do not have headphones plugged in or blue-tooth headphones connected and turned on. I’m guessing that the audio would also not pause when the screen is turned off if I had a blue-tooth speaker connected and turned on.

Prologue (and custom agent) is a great solution for audiobooks in Plex
https://prologue.audio/

2 Likes

The Chronicle dev is back. He apparently just had burnout for a while.

https://www.reddit.com/r/ChronicleApp/comments/lxqoye/update/

https://www.reddit.com/r/ChronicleApp/comments/lxqoye/update/

Hey all,

Sorry for the lack of contact over the last few months. Got a little burnt out developing the app. I felt bad about that so I didn’t check the Reddit much, and here we are

I’ve been working on a release to fix a few of the main issues posted here, plus some things I’d already been working on. It consists of:

  • Rewrite of the downloader to work with SD card on all devices (done)
  • Highlight the current chapter in the chapter list (done)
  • Manually set “listened” status on items (done, needs testing)
  • Allow forced progress syncing (wip)

Future things to be addressed:

  • Look into potential pin auth issues
  • Downloads disappearing. I need to dig more into how Plex identifies tracks when it syncs them, but that will take time

Regarding open sourcing the project: I haven’t made an decisions about this, but I’m warming to the idea. This is already a fairly long post, but I’ll post my thoughts/discuss in the comments

Thought I’d throw this out there before I published anything in case I overlooked anything big

Edit: Also, I’ll catch up on old posts and DMs later today

2 Likes

This has been a game changer for me, along with the metadata process described above. SO appreciative of the Prologue devs!

Thanks for the suggestion, I’m trying it out now. I lost the ability to change playback speed on the last iOS update so this looks to do nicely.

1 Like