My love for Plex is not a secret. I’ve written about Plex many times before on this site. The same goes for my love of ffmpeg. As wonderful a tool as ffmpeg is, occasionally it lets me down.

I recently ripped a two-part concert BluRay for easier playback on Plex. I did so using MakeMKV, as always. This had the advantage of preserving the chapter markers in each disc; I could easily go in using Subler and rename all the canned names, say Chapter 20, to useful names, such as While My Guitar Gently Weeps.

My problem came in when I wanted to merge the two files. Using my normal ffmpeg incantation did not automatically carry the chapters across to the merged file.

# filelist.txt:
# file clapton1.mp4
# file clapton2.mp4

ffmpeg -f concat -i filelist.txt -c copy clapton-joined.mp4

What I wanted was for both sets of chapters to be preserved, with the chapters in the second file automatically offsetting themselves by the duration of the first file. Thus, if the first file is two hours, chapter one of the second file would start at two hours, not at 0 minutes.

Perhaps there’s a ffmpeg incantation I can use to accomplish what I wanted, but if so, I couldn’t find it.

So, I turned to something I’ve been using more and more lately: Python.

I should state up front I’m a terrible Python developer, and am probably breaking every known coding convention and/or best practice. However, on the off chance someone is looking for a script to do exactly the above, I’ve written one.

This script is run like this, for example:

python3 ./ clapton1.mp4 clapton2.mp4 Clapton-Full.mp4

Assuming you have two files with the chapters marked and named as you wish, the script does the following:

  1. Uses ffprobe to get the duration of the first file (clapton1.mp4 in our example)
  2. Gets all the metadata — including chapter information — from the first file
  3. Reads the second file’s chapter list using ffprobe (clapton2.mp4 in our example)
  4. Offsets each of the second file’s chapter’s timestamps by the duration found in step #1
  5. Appends this new chapter information to the metadata found in step #2
  6. Writes this combined metadata, and a file list, to disk
  7. Uses ffmpeg to merge the two files, and install chapters using the combined metadata found in step #5
  8. Cleans up after itself

Again, there are surely easier ways to do this, but this seems to have worked with my example files. I’ll be trying it again on other ripped concert films shortly.

You can find the script as a gist on Github.

Though I’m not actively requesting feedback/pointers/tips on how to write better Python, if you’re bored, please feel free to fork that gist and improve it as you see fit. (I’d prefer a fork rather than comments on that gist, if you don’t mind, please.)

However, if you happen to know of an incantation I can use directly with ffmpeg to make this all happen in one step, I’m all ears.