| namespace | aiwg |
| platforms | ["all"] |
| name | cover-art-embedding |
| description | Patterns for finding, processing, and embedding cover artwork into media files |
| category | media-curator |
Cover Art Embedding Skill
Concrete patterns for finding high-quality cover artwork, processing it for optimal size and format, and embedding it into audio and video files.
Artwork Sources
MusicBrainz Cover Art Archive (Primary)
MusicBrainz Cover Art Archive (CAA) is the authoritative source for album artwork.
Get Front Cover by Release MBID:
curl -s "https://coverartarchive.org/release/{mbid}/front" -o cover.jpg
curl -s "https://coverartarchive.org/release/5c004fe3-6e96-3f43-9a85-16e5be8805fa/front" -o blue-cover.jpg
Check if Cover Exists:
if curl -s -I "https://coverartarchive.org/release/${mbid}/front" | grep -q "200 OK"; then
echo "Cover available"
else
echo "No cover found"
fi
Get All Available Images:
curl -s "https://coverartarchive.org/release/${mbid}" | jq .
curl -s "https://coverartarchive.org/release/${mbid}" | \
jq -r '.images[] | select(.front == true) | .image'
url=$(curl -s "https://coverartarchive.org/release/${mbid}" | \
jq -r '.images[] | select(.front == true) | .image' | head -1)
curl -s "$url" -o cover.jpg
fanart.tv API
fanart.tv provides high-quality artist images, album covers, and logos.
Get Artist Images:
FANART_API_KEY="your-api-key"
curl -s "https://webservice.fanart.tv/v3/music/${mbid}?api_key=${FANART_API_KEY}"
curl -s "https://webservice.fanart.tv/v3/music/${mbid}?api_key=${FANART_API_KEY}" | \
jq -r '.albums."'"$album_mbid"'".albumcover[0].url'
curl -s "https://webservice.fanart.tv/v3/music/${mbid}?api_key=${FANART_API_KEY}" | \
jq -r '.artistbackground[0].url'
curl -s "https://webservice.fanart.tv/v3/music/${mbid}?api_key=${FANART_API_KEY}" | \
jq -r '.hdmusiclogo[0].url'
Download Artwork:
url=$(curl -s "https://webservice.fanart.tv/v3/music/${mbid}?api_key=${FANART_API_KEY}" | \
jq -r '.albums."'"$album_mbid"'".albumcover[0].url')
curl -s "$url" -o cover.jpg
Video Thumbnail Extraction
Extract cover artwork from video frames.
Using yt-dlp (if video was downloaded with thumbnail):
yt-dlp --write-thumbnail --convert-thumbnails jpg "https://youtube.com/watch?v=..."
Using ffmpeg (extract from video):
ffmpeg -i input.mp4 -ss 00:00:10 -frames:v 1 -q:v 2 thumbnail.jpg
ffmpeg -i input.mp4 -vf "select=eq(pict_type\,I)" -frames:v 1 -q:v 2 thumbnail.jpg
duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4)
timestamp=$(echo "$duration * 0.25" | bc)
ffmpeg -i input.mp4 -ss "$timestamp" -frames:v 1 -q:v 2 thumbnail.jpg
ffmpeg -i input.mp4 -t 60 -vf "select=eq(pict_type\,I)" -vsync vfr -q:v 1 frames-%03d.jpg
Local Artwork Files
Scan for existing artwork in standard locations:
for name in cover.jpg Cover.jpg folder.jpg Folder.jpg albumart.jpg AlbumArt.jpg; do
if [ -f "$name" ]; then
echo "Found: $name"
break
fi
done
if [ -f "../cover.jpg" ]; then
cp "../cover.jpg" .
fi
largest=$(find . -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.png" \) -exec ls -s {} \; | \
sort -rn | head -1 | awk '{print $2}')
echo "Largest image: $largest"
Image Processing
Resize for Mobile Optimization
Reduce image size for faster loading and smaller file sizes:
brew install imagemagick
sudo apt install imagemagick
convert input.jpg -resize 1200x1200 output.jpg
convert input.jpg -resize 1200x1200 -quality 85 output.jpg
convert input.jpg -resize 300x300 thumbnail.jpg
for img in *.jpg; do
convert "$img" -resize 1200x1200 -quality 85 "${img%.jpg}-resized.jpg"
done
Format Conversion
Convert between image formats:
convert input.png output.jpg
convert input.webp output.jpg
convert input.jpg output.png
for img in *.png; do
convert "$img" "${img%.png}.jpg"
done
Crop to Square
Crop non-square images to square aspect ratio:
convert input.jpg -gravity center -crop 1:1 +repage output.jpg
convert input.jpg -crop 1200x1200+0+0 +repage output.jpg
convert input.jpg -define trim:percent-background=0% -trim +repage -resize 1200x1200 output.jpg
Remove Metadata (Privacy)
Strip EXIF data before embedding:
convert input.jpg -strip output.jpg
exiftool -all= input.jpg
for img in *.jpg; do
convert "$img" -strip "${img%.jpg}-clean.jpg"
done
Embedding Artwork
Opus Files (opustags)
opustags input.opus --set-cover cover.jpg -o output.opus
opustags -i input.opus --set-cover cover.jpg
opustags input.opus | grep -i picture
MP4 Files (ffmpeg)
ffmpeg -i input.mp4 -i cover.jpg \
-map 0 -map 1 \
-c copy \
-disposition:v:1 attached_pic \
output.mp4
ffmpeg -i input.mp4 -i cover.jpg \
-map 0 -map 1 \
-c copy \
-disposition:v:1 attached_pic \
-metadata:s:v:1 title="Album cover" \
-metadata:s:v:1 comment="Cover (front)" \
output.mp4
ffprobe -v error -select_streams v -show_entries stream=codec_name,codec_type,disposition input.mp4
MP3 Files (ffmpeg)
ffmpeg -i input.mp3 -i cover.jpg \
-map 0 -map 1 \
-c copy \
-id3v2_version 3 \
-metadata:s:v title="Album cover" \
-metadata:s:v comment="Cover (front)" \
output.mp3
ffmpeg -i input.mp3 -an -vcodec copy test-extracted-cover.jpg
FLAC Files (ffmpeg)
ffmpeg -i input.flac -i cover.jpg \
-map 0 -map 1 \
-c copy \
-disposition:v:0 attached_pic \
output.flac
metaflac --import-picture-from=cover.jpg input.flac
Batch Embedding
Embed Same Cover into All Files
for file in *.opus; do
opustags -i "$file" --set-cover cover.jpg
echo "Embedded: $file"
done
for file in *.mp3; do
ffmpeg -i "$file" -i cover.jpg \
-map 0 -map 1 -c copy \
-id3v2_version 3 \
-metadata:s:v title="Album cover" \
"${file%.mp3}-covered.mp3"
mv "${file%.mp3}-covered.mp3" "$file"
done
Embed Different Covers per Album
for album_dir in */; do
cover=$(find "$album_dir" -maxdepth 1 -iname "cover.jpg" | head -1)
if [ -n "$cover" ]; then
for file in "$album_dir"/*.opus; do
opustags -i "$file" --set-cover "$cover"
done
echo "Processed: $album_dir"
else
echo "No cover found: $album_dir"
fi
done
Download and Embed from MusicBrainz
#!/bin/bash
for file in *.opus; do
artist=$(opustags "$file" | grep "ARTIST=" | cut -d= -f2)
album=$(opustags "$file" | grep "ALBUM=" | cut -d= -f2)
artist_enc=$(echo "$artist" | jq -sRr @uri)
album_enc=$(echo "$album" | jq -sRr @uri)
mbdata=$(curl -s "https://musicbrainz.org/ws/2/release/?query=artist:${artist_enc}%20AND%20release:${album_enc}&fmt=json" \
-H "User-Agent: MediaCurator/1.0")
mbid=$(echo "$mbdata" | jq -r '.releases[0].id')
if curl -s "https://coverartarchive.org/release/${mbid}/front" -o "/tmp/cover-${mbid}.jpg"; then
opustags -i "$file" --set-cover "/tmp/cover-${mbid}.jpg"
echo "Embedded cover: $file"
else
echo "No cover found: $file"
fi
1
Canonical Artwork Directory
From field testing: use a single artwork/ directory for all artwork files, not scattered copies.
Directory Structure
artwork/
├── albums/
│ ├── blue.jpg
│ ├── court-and-spark.jpg
│ ├── hejira.jpg
│ └── clouds.jpg
├── artists/
│ ├── joni-mitchell-1970.jpg
│ ├── joni-mitchell-1976.jpg
│ └── joni-mitchell-2000.jpg
├── live/
│ ├── isle-of-wight-1970.jpg
│ └── carnegie-hall-1969.jpg
├── logos/
│ └── joni-mitchell-logo.png
├── promotional/
│ ├── blue-era-promo.jpg
│ └── court-and-spark-promo.jpg
└── ATTRIBUTION.md
Populate Artwork Directory
mkdir -p artwork/{albums,artists,live,logos,promotional}
cd artwork/albums
curl -s "https://coverartarchive.org/release/{mbid}/front" -o blue.jpg
curl -s "https://coverartarchive.org/release/{mbid}/front" -o court-and-spark.jpg
cd ../artists
curl -s "https://fanart.tv/..." -o joni-mitchell-1970.jpg
cd ../live
ffmpeg -i ../../video/isle-of-wight-1970.mp4 -ss 00:01:30 -frames:v 1 -q:v 2 isle-of-wight-1970.jpg
Embed from Canonical Directory
for file in music/Joni\ Mitchell/Blue/*.opus; do
opustags -i "$file" --set-cover artwork/albums/blue.jpg
done
ln -s ../../artwork/albums/blue.jpg music/Joni\ Mitchell/Blue/cover.jpg
ATTRIBUTION.md
Record source and rights for all artwork:
# Artwork Attribution
## Albums
### blue.jpg
- Source: MusicBrainz Cover Art Archive
- URL: https://coverartarchive.org/release/5c004fe3-6e96-3f43-9a85-16e5be8805fa
- License: Public Domain
- Uploaded by: user123
- Date: 2015-03-20
### court-and-spark.jpg
- Source: fanart.tv
- URL: https://fanart.tv/music/...
- License: Fair Use
- Date: 2018-07-15
## Artists
### joni-mitchell-1970.jpg
- Source: Extracted from "Live at Isle of Wight 1970" video
- License: Fair Use
- Date: 2026-02-14
## Live
### isle-of-wight-1970.jpg
- Source: Video frame extraction (ffmpeg)
- Original video: Live at Isle of Wight 1970.mp4
- License: Fair Use
- Date: 2026-02-14
Extract Embedded Artwork
From Opus Files
ffmpeg -i input.opus -an -vcodec copy cover.jpg
From MP4 Files
ffmpeg -i input.mp4 -map 0:v -map -0:V -c copy cover.jpg
ffmpeg -i input.mp4 -map 0:v -c copy "stream-%d.jpg"
From MP3 Files
ffmpeg -i input.mp3 -an -vcodec copy cover.jpg
id3v2 -l input.mp3
id3v2 --APIC input.mp3 > cover.jpg
From FLAC Files
metaflac --export-picture-to=cover.jpg input.flac
ffmpeg -i input.flac -an -vcodec copy cover.jpg
Quality Checks
Verify Artwork is Embedded
opustags input.opus | grep -i picture
ffprobe -v error -select_streams v -show_entries stream=disposition:stream_tags input.mp4
ffprobe -v error -show_entries format_tags input.mp3 | grep -i picture
ffmpeg -i input.mp3 -an -vcodec copy test.jpg
ls -lh test.jpg
Check Image Dimensions
identify cover.jpg
ffprobe -v error -select_streams v:0 -show_entries stream=width,height cover.jpg
Verify File Size
ls -lh cover.jpg
Troubleshooting
Cover Not Displaying in Media Player
ffprobe -v error -show_entries format_tags input.mp3
ffmpeg -i input.mp4 -i cover.jpg -map 0 -map 1 -c copy \
-disposition:v:1 attached_pic \
output.mp4
Image Format Not Supported
convert input.png output.jpg
opustags -i input.opus --set-cover output.jpg
Image Too Large (Slow Loading)
convert cover.jpg -resize 1200x1200 -quality 85 cover-optimized.jpg
opustags -i input.opus --set-cover cover-optimized.jpg
MusicBrainz Cover Not Available
curl -s "https://webservice.fanart.tv/v3/music/${mbid}?api_key=${FANART_API_KEY}" | \
jq -r '.albums."'"$album_mbid"'".albumcover[0].url'
Complete Workflow Example
#!/bin/bash
file="$1"
album=$(opustags "$file" | grep "ALBUM=" | cut -d= -f2)
artist=$(opustags "$file" | grep "ARTIST=" | cut -d= -f2)
artist_enc=$(echo "$artist" | jq -sRr @uri)
album_enc=$(echo "$album" | jq -sRr @uri)
mbdata=$(curl -s "https://musicbrainz.org/ws/2/release/?query=artist:${artist_enc}%20AND%20release:${album_enc}&fmt=json" \
-H "User-Agent: MediaCurator/1.0")
mbid=$(echo "$mbdata" | jq -r '.releases[0].id')
cover_url="https://coverartarchive.org/release/${mbid}/front"
curl -s "$cover_url" -o "/tmp/cover-${mbid}.jpg"
convert "/tmp/cover-${mbid}.jpg" \
-resize 1200x1200 \
-quality 85 \
-strip \
"/tmp/cover-${mbid}-processed.jpg"
opustags -i "$file" --set-cover "/tmp/cover-${mbid}-processed.jpg"
artist_safe=$(echo | )
album_safe=$( | )
-p
>> artwork/ATTRIBUTION.md <<
See Also
References
- @$AIWG_ROOT/agentic/code/addons/aiwg-utils/rules/human-authorization.md — Seek explicit authorization before overwriting existing embedded artwork
- @$AIWG_ROOT/agentic/code/frameworks/media-curator/skills/metadata-tagging/SKILL.md — Metadata tagging skill used alongside cover art embedding for complete file tagging
- @$AIWG_ROOT/agentic/code/frameworks/media-curator/skills/tag-collection/SKILL.md — Tag collection skill that orchestrates metadata and artwork embedding together
- @$AIWG_ROOT/agentic/code/frameworks/media-curator/skills/integrity-verification/SKILL.md — Verify file integrity after embedding artwork