Post

Embedding Metadata & Posters into Video Files Using tinyMediaManager

Embedding Metadata & Posters into Video Files Using tinyMediaManager

Managing a digital video collection isn’t just about keeping files organized - it’s about having rich metadata like titles, genres, descriptions, and artwork that provide a polished media library experience. Tools like tinyMediaManager make it easy to fetch and manage this metadata, but the data is typically saved in external .nfo and image files.

To embed this metadata directly into the video files, we’ll combine tinyMediaManager with the mighty FFmpeg, using nothing but a post-processing script - and no external tools beyond FFmpeg itself. We’ll also use JMTE templating, a built-in feature of tinyMediaManager, to streamline the process and avoid parsing .nfo files manually.

This approach works on Windows, macOS, and Linux for tinyMediaManager versions starting from v5.1.7.

ATTENTION: Attaching metadata alters your video files! Changed video files are detected by the “update data sources” action in tinyMediaManager as new/replaced files!


⚙️ What You’ll Need

  • tinyMediaManager v5.1.7+
  • FFmpeg (4.3+ is ideal - tinyMediaManager already ships an up to date FFmepg which we will use)
  • A terminal or command-line shell
  • Basic scripting skills (Bash or Batch)

🧩 What is JMTE?

JMTE stands for Java Minimal Template Engine. It’s a lightweight templating language used in tinyMediaManager to insert metadata variables into scripts, filenames, and post-processing commands.

Instead of parsing .nfo XML files, tinyMediaManager can inject metadata directly into command-line arguments using placeholders like:

1
2
3
4
5
${movie.title}
${movie.year}
${movie.plot}
${movie.mainVideoFile.file}
${movie.artworkMap.POSTER.file}

This makes scripting faster, simpler, and more reliable.


🛠️ Script Setup

Depending on your system, you need to either use a shellscript (Linux, macOS) or a Windows Batch file/PowerShell script (Windows). You should place the script into the same folder as the ffmpeg binary is - if you want to use the shipped ffmpeg, this would be in the addons folder of your tinyMediaManager installation. The easiest way to find the addons folder of your installation would be to open tinyMediaManager itself and use the action “Tools -> Open content folder” and locate the subfolder addons.

🐧 Linux/macOS Shell Script: embed-metadata.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/bin/bash
# Script: embed-metadata.sh

set -e

VIDEO="$1"
TITLE="$2"
YEAR="$3"
PLOT="$4"
POSTER="$5"

if [ -z "$VIDEO" ] || [ ! -f "$VIDEO" ]; then
  echo "Error: Video file is missing or does not exist."
  exit 1
fi

EXT="${VIDEO##*.}"
EXT_LOWER=$(echo "$EXT" | tr '[:upper:]' '[:lower:]')

case "$EXT_LOWER" in
  mp4|mkv)
    CAN_EMBED_POSTER=true
    ;;
  mov)
    CAN_EMBED_POSTER=false
    ;;
  *)
    echo "Error: Unsupported video format '$EXT_LOWER'. Supported formats: mp4, mkv, mov."
    exit 1
    ;;
esac

# Temporary output file
TMP_OUTPUT="${VIDEO}.tmp.${EXT_LOWER}"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CMD=("$SCRIPT_DIR/ffmpeg" -y -i "$VIDEO")

if [ "$CAN_EMBED_POSTER" = true ] && [ -f "$POSTER" ]; then
  CMD+=(-i "$POSTER" -map 0 -map 1 -disposition:v:1 attached_pic)
else
  CMD+=(-map 0)
fi

CMD+=(
  -metadata title="$TITLE"
  -metadata year="$YEAR"
  -metadata comment="$PLOT"
  -c copy "$TMP_OUTPUT"
)

# Run FFmpeg command
echo "Running FFmpeg..."
if "${CMD[@]}" > /dev/null 2>&1; then
  mv -f "$TMP_OUTPUT" "$VIDEO"
  echo "Successfully updated metadata in '$VIDEO'"
else
  echo "FFmpeg failed. Original file left untouched."
  rm -f "$TMP_OUTPUT"
  exit 1
fi

Make it executable:

1
chmod +x /path/to/embed-metadata.sh

🪟 Windows Batch Script: embed-metadata.bat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@echo off
setlocal enabledelayedexpansion

set "VIDEO=%~1"
set "TITLE=%~2"
set "YEAR=%~3"
set "PLOT=%~4"
set "POSTER=%~5"

if not exist "%VIDEO%" (
    echo Error: Video file is missing or does not exist.
    exit /b 1
)

set "EXT=%~x1"
set "EXT_LOWER=%EXT:.=%"
set "EXT_LOWER=%EXT_LOWER:~1%"
set "EXT_LOWER=%EXT_LOWER:~0,3%"
set "EXT_LOWER=%EXT_LOWER:~0,3%"

if /i "%EXT_LOWER%"=="mp4" (
    set "CAN_EMBED_POSTER=true"
) else if /i "%EXT_LOWER%"=="mkv" (
    set "CAN_EMBED_POSTER=true"
) else if /i "%EXT_LOWER%"=="mov" (
    set "CAN_EMBED_POSTER=false"
) else (
    echo Error: Unsupported video format '%EXT_LOWER%'. Supported formats: mp4, mkv, mov.
    exit /b 1
)

set "TMP_OUTPUT=%VIDEO%.tmp.%EXT_LOWER%"
set "SCRIPT_DIR=%~dp0"

if "%CAN_EMBED_POSTER%"=="true" if exist "%POSTER%" (
    "%SCRIPT_DIR%ffmpeg.exe" -y -i "%VIDEO%" -i "%POSTER%" -map 0 -map 1 -disposition:v:1 attached_pic ^
        -metadata title="%TITLE%" -metadata year="%YEAR%" -metadata comment="%PLOT%" -c copy "%TMP_OUTPUT%" >nul 2>&1
) else (
    "%SCRIPT_DIR%ffmpeg.exe" -y -i "%VIDEO%" -map 0 ^
        -metadata title="%TITLE%" -metadata year="%YEAR%" -metadata comment="%PLOT%" -c copy "%TMP_OUTPUT%" >nul 2>&1
)

if exist "%TMP_OUTPUT%" (
    move /Y "%TMP_OUTPUT%" "%VIDEO%" >nul
    echo Successfully updated metadata in "%VIDEO%"
) else (
    echo FFmpeg failed. Original file left untouched.
    exit /b 1
)

🪟 Windows Powershell Script: embed-metadata.ps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
param (
    [string]$Video,
    [string]$Title,
    [string]$Year,
    [string]$Plot,
    [string]$Poster
)

if (-not (Test-Path $Video)) {
    Write-Error "Error: Video file is missing or does not exist."
    exit 1
}

$Ext = [System.IO.Path]::GetExtension($Video).TrimStart('.').ToLower()

switch ($Ext) {
    "mp4" { $CanEmbedPoster = $true }
    "mkv" { $CanEmbedPoster = $true }
    "mov" { $CanEmbedPoster = $false }
    default {
        Write-Error "Error: Unsupported video format '$Ext'. Supported formats: mp4, mkv, mov."
        exit 1
    }
}

$TmpOutput = "$Video.tmp.$Ext"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition

$Args = @("-y", "-i", $Video)

if ($CanEmbedPoster -and (Test-Path $Poster)) {
    $Args += @("-i", $Poster, "-map", "0", "-map", "1", "-disposition:v:1", "attached_pic")
} else {
    $Args += @("-map", "0")
}

$Args += @(
    "-metadata", "title=$Title",
    "-metadata", "year=$Year",
    "-metadata", "comment=$Plot",
    "-c", "copy",
    $TmpOutput
)

Write-Host "Running FFmpeg..."
$ffmpeg = Join-Path $ScriptDir "ffmpeg.exe"
$process = Start-Process -FilePath $ffmpeg -ArgumentList $Args -NoNewWindow -Wait -PassThru -RedirectStandardOutput $null -RedirectStandardError $null

if ($process.ExitCode -eq 0 -and (Test-Path $TmpOutput)) {
    Move-Item -Force $TmpOutput $Video
    Write-Host "Successfully updated metadata in '$Video'"
} else {
    Write-Error "FFmpeg failed. Original file left untouched."
    if (Test-Path $TmpOutput) {
        Remove-Item $TmpOutput -Force
    }
    exit 1
}

📁 Configure Post-Processing in tinyMediaManager

  1. Go to SettingsMovies / TV showsPost-Processing
  2. Add a new Post-Processing entry:
    • Name as you wish (e.g. Embed metadata)
    • Path to the script (absolute path - use the file explorer to find the script in the addons folder)
    • Script arguments:
      1
      2
      3
      4
      5
      
      "${movie.mainVideoFile.file}"
      "${movie.title}"
      "${movie.year}"
      "${movie.plot}"
      "${movie.artworkMap.POSTER.file}"
      

tinyMediaManager Post-Process

Always test scripts with a sample file before bulk tagging


🧠 Final Thoughts

Embedding metadata directly into your video files means your collection is self-contained, portable, and ready for any media player. By combining tinyMediaManager, JMTE templating, and FFmpeg, you gain an efficient workflow without additional tools or manual steps.

This script-based approach is clean, fast, and platform-independent. It’s a fantastic way to bring professional polish to your personal media collection - fully automated, fully yours.

This post is licensed under CC BY 4.0 by the author.