Index


If you use FFmpeg to do a lot of re-encoding/remuxing of your media files and have wanted a way to automatically insert the movie/show name as clean metadata, keep reading..

In order to make this work, the prerequisite is to ensure the name of the movie/show is in the file name itself. If you can't guarantee that, you should probably look for a different solution such as extracting the name from the container metadata.

πŸ“Œ
TIP: If you are not fluent with FFmpeg syntax, I recommend you click here for a big list of my example commands or visit the FFMPEG HOW-TO which is now a menu link at the top of every page.

After lots of trial & error, I have found what I believe to be the best method requiring the fewest number of modifications of the sed search script.
To reiterate: this extracts the movie/show name from the file name and inserts it into the title metadata field, which is a compatible and standard MKV & MP4 container metadata field.

πŸ‘Ώ
ANOTHER TIP: Use gsed for GNU sed instead of sed on BSD platforms. Read about the differences between BSD sed and GNU sed.
  1. Extract the movie/show name from the file name:
sed -E "s/\./\ /g;s/\w+/\U&/g;s/^(.*(S[[:digit:]]+E[[:digit:]]+|\(?[[:digit:]]{4}\)?[^P])).*(MKV|MP4)$/\1/" <INPUT>

Command Breakdown

sed -E

  • sed: The stream editor, a command-line tool for parsing and transforming text.
  • -E: This flag enables extended regular expressions (EREs). This simplifies the syntax by removing the need to escape special characters like +, ?, |, (, and )

The entire command is composed of three substitution expressions, each separated by a semicolon ;.

1. s/\./\ /g

  • s: The substitute command.
  • /\./: This is the pattern to be matched.
    • \. is an escaped period, which matches a literal period character .. Without the backslash, a period is a wildcard that matches any single character.
  • /\ /: This is the replacement string. It replaces the matched period with a single space.
  • g: The global flag, which means the substitution should be applied to all matches on the line, not just the first one. 

Effect: This step replaces all periods in the input string with spaces. For example, My.Show.S01E01.mkv becomes My Show S01E01 mkv.

2. s/\w+/\U&/g

  • s: The substitute command.
  • /\w+/: The pattern to be matched.
    • \w matches any "word" character (letters, numbers, and underscore).
    • + matches one or more occurrences of the preceding character, in this case, a word character.
  • /\U&/: The replacement string.
    • \U is a special escape sequence that converts all subsequent characters in the replacement string to uppercase.
    • & is a back-reference that represents the entire matched pattern (\w+).
  • g: The global flag, which ensures that every "word" on the line is converted. 

Effect: This step capitalizes every word in the input string. For example, My Show s01e01 mkv becomes MY SHOW S01E01 MKV.

3. s/^(.*(S[[:digit:]]+E[[:digit:]]+|\(?[[:digit:]]{4}\)?[^P])).*(MKV|MP4)$/\1/This is the most complex step, and it performs the final cleanup.

  • s: The substitute command.
  • ^...$: The pattern matches the entire line, from the beginning (^) to the end ($).
  • ^(.*(...|...)): The core of the regex is a capturing group ((...)) that holds the intended filename.
    • .*: Greedily matches any character (.) any number of times (*) until it finds the next part of the pattern.
    • (S[[:digit:]]+E[[:digit:]]+| \(?[[:digit:]]{4}\)?[^P]): This is an alternation (|) matching one of two possible patterns commonly found in filenames.
      • S[[:digit:]]+E[[:digit:]]+: Matches a show's season and episode format.
        • S: The literal character S.
        • [[:digit:]]+: One or more digit characters.
        • E: The literal character E.
        • [[:digit:]]+: One or more digit characters.
      • \(?[[:digit:]]{4}\)?[^P]: Matches a four-digit year, possibly in parentheses.
        • \(?: An optional opening parenthesis.
        • [[:digit:]]{4}: Exactly four digits.
        • \)?: An optional closing parenthesis.
        • [^P]: Any character that is not the letter P (to avoid matching the resolution such as 1080P, which is normally after the year).
  • .*: Matches all remaining characters until the end of the line.
  • (MKV|MP4): This is another capturing group, though it is not referenced in the replacement. It matches the common file extensions MKV or MP4.
  • $: Matches the end of the line.
  • /\1/: The replacement string uses the back-reference \1, which refers to the content captured by the first set of parentheses (...) described in the 3rd bullet-point under step 3.

Effect: This step finds the video file extension and any junk (like resolution, release group, or quality tags) and removes it, leaving only the series/episode or year information. For example, MY SHOW S01E01 1080P HDTV X264 MKV becomes MY SHOW S01E01 and MY MOVIE (2025) 1080P WEB-DL X265 MP4 becomes MY MOVIE (2025)

Shell Script Syntax using a For Loop

This shows the shell syntax involving the variable f in the for loop:

for f in <INPUT>; do ffmpeg -i "$f" -map 0 -metadata title="$(sed -E "s/\./\ /g;s/\w+/\U&/g;s/^(.*(S[[:digit:]]+E[[:digit:]]+|\(?[[:digit:]]{4}\)?[^P])).*(MKV|M4V|WEBM|MP4|MOV|MPG|AVI)$/\1/" <<<"${f}")" -codec copy <OUTPUT>; done

Simplified & Full Working Shell Script Examples

# SIMPLIFIED WORKING EXAMPLE ONE-LINER:

for f in *.mkv; do ffmpeg -i "$f" -map 0 -metadata title="$(sed -E 's/\./\ /g;s/\w+/\U&/g;s/^(.*(S[[:digit:]]+E[[:digit:]]+|\(?[[:digit:]]{4}\)?[^P])).*(MKV|MP4)$/\1/' <<<"${f}")" -codec copy "${f/.mkv/-modified.mkv}"; done

# SIMPLIFIED WORKING EXAMPLE MULTI-LINER:

for f in *.mkv; do ffmpeg -i "$f" -map 0 -metadata title="$(sed -E 's/\./\ /g;s/\w+/\U&/g;'\
's/^(.*(S[[:digit:]]+E[[:digit:]]+|\(?[[:digit:]]{4}\)?[^P])).*(MKV|MP4)$/\1/' <<<"${f}")" \
-codec copy "${f/.mkv/-modified.mkv}"; done

# FULL WORKING EXAMPLE ONE-LINER:

for f in *.mkv; do ffmpeg -loglevel verbose -hide_banner -y -i "$f" -map 0:v:0 -map 0:a:m:language:eng -map "0:s?" -dn -metadata title="$(sed -E 's/\./\ /g;s/\w+/\U&/g;s/^(.*(S[[:digit:]]+E[[:digit:]]+|\(?[[:digit:]]{4}\)?[^P])).*(MKV|M4V|WEBM|MP4|MOV|MPG|AVI)$/\1/' <<<"${f}")" -metadata:s:v:0 title= -metadata comment="Remuxed by visualblind $(date -Iseconds)" -metadata:s:v:0 language=eng -disposition:v:0 default -disposition:a:0 default -c:v copy -channel_layout "5.1" -c:a aac -c:s copy .working/"${f}"; done

# FULL WORKING EXAMPLE MULTI-LINER:

for f in *.mkv; do ffmpeg -loglevel verbose -hide_banner -y -i "$f" -map 0:v:0 -map \
0:a:m:language:eng -map "0:s?" -dn -metadata title=\
"$(sed -E 's/\./\ /g;s/\w+/\U&/g;s/^(.*(S[[:digit:]]+E[[:digit:]]+|'\
'\(?[[:digit:]]{4}\)?[^P])).*(MKV|M4V|WEBM|MP4|MOV|MPG|AVI)$/\1/' <<<"${f}")" \
-metadata:s:v:0 title= -metadata comment="Remuxed by visualblind $(date -Iseconds)" \
-metadata:s:v:0 language=eng -disposition:v:0 default -disposition:a:0 default \
-c:v copy -channel_layout "5.1" -c:a aac -c:s copy .working/"${f}"; done

Title Field Metadata Output from Sed

Action Result
Input my.movie.s01e01.720p.hdtv.x264.mkv
After 1st sed my movie s01e01 720p hdtv x264 mkv
After 2nd sed MY MOVIE S01E01 720P HDTV X264 MKV
After 3rd sed MY MOVIE S01E01
πŸ’‘
FYI: The title metadata field in FFmpeg is ouput as the Movie name field when using the mediainfo tool.

Mediainfo Output Example

General
Complete name                            : Clarksons.Farm.S04E01.1080p.AMZN.WEB-DL.AAC5.1.H264.mp4
Format                                   : MPEG-4
Format profile                           : Base Media
Frame rate                               : 25.000 FPS
Movie name                               : CLARKSONS FARM S04E01
Writing application                      : Lavf60.16.100

Obsolete Full Working Examples (Don't Use)

# FFMPEG COMMAND FOR MOVIES:

for f in *.mp4; do ffmpeg -i "$f" -map 0 -movflags faststart -metadata title="$(sed -E 's/\./\ /g;s/\w+/\U&/g;s/^([A-Za-z -]+(\(?[[:digit:]]{4}\)?)?([^1080PI]|[^720PI]|[A-Za-z0-9 -])?(S[[:digit:]]{1,2}E[[:digit:]]{1,2})?).*$/\1/' <<<"${f}")" -codec copy .working/"$f"; done


# FFMPEG COMMAND FOR SHOWS:

for f in *.mkv; do ffmpeg -i "$f" -map 0 -metadata title="$(sed -E 's/\./\ /g;s/\w+/\U&/g;s/^([A-Za-z0-9 -]+\(?[[:digit:]]{4}\)?[^1080pPiI]|[A-Za-z0-9 -]+S[[:digit:]]{1,2}E[[:digit:]]{1,2}).*$/\1/' <<<"${f}")" -codec copy .working/"$f"; done

If you have any questions/comments regarding this article, click here or scroll down below (login isn't required to post comments and there's no waiting period).

Supported MP4 Metadata Keys with FFmpeg
The following table lists the supported MP4 container metadata key names in FFmpeg.
FFmpeg Map English Subtitles or Audio Stream Only
Dynamic FFmpeg Subtitle Stream Mapping by Language You can map English subs only by using -map 0:s:m:language:eng. With FFmpeg you can dynamically map streams which match certain criteria such as language that you specify. If you’re looking for the 3-letter language codes go to https:
FFmpeg Batch Transcode Audio
Recently I have been dealing with transcoding media files for my streaming site travisflix and performing ad-hoc media conversions is no longer realistic. I strongly recommend checking out my FFmpeg Examples to give you a head start if you’re not familiar with deep diving in FFmpeg details. Before you