youtube-dl + ffmpeg: Import description and URL of an original video to ID3 tags

Following bundle is used to download and encode audio:

/usr/local/bin/youtube-dl --playlist-reverse -o "%(upload_date)s %(title)s.%(ext)s" --write-annotations --download-archive ".archive" --add-metadata --write-sub --sub-lang en --write-auto-sub -f "bestaudio[ext=m4a]" -i "https://www.youtube.com/channel/CHANNEL_ID"
for name in *.m4a; do
  /usr/bin/ffmpeg -y -hide_banner -loglevel info -i "$name" -metadata artist="ArtistName" -metadata album="AlbumName" -acodec libmp3lame -ar 44100 -ac 1 -ab 192k "${name%.*}_192.mp3"
done

When the resulting file is viewed in a hex viewer, the description of the original video can be viewed in binary form, but when the file is loaded in Tag&Rename 3.5.5, there is nothing in the standard "Description" ID3 tag.

Also the standard "URL" ID3 tag is neither shown in Tag&Rename nor present in a binary form.

How to import both, description and URL, to the right places?


Solution 1:

Use webm, not m4a

The M4A muxer won't include URL metadata, so your MP3 command didn't have it to begin with.

Use WebM instead. In youtube-dl use -f "bestaudio[ext=webm]" instead of -f "bestaudio[ext=m4a]"

So now the URL metadata will be included. However, that only partially solves the URL and comment/description metadata issue.

ffmpeg MP3 metadata is weird

For some reason ffmpeg uses User defined text information frame (TXXX) for comments/description and URL instead of the proper tag identifier. So although the metadata is there your player/tagger may ignore it.

I'm not aware of a tool that allows you to reassign existing tags, so consider asking at softwarerecs.stackexchange.com.

Otherwise, you'll have to do it manually by using a tool such as eyeD3 after encoding the MP3 with ffmpeg using metadata from the WebM file:

eyeD3 --user-url-frame ":$(ffprobe -v error -show_entries format_tags=PURL -of csv=p=0 "input.webm")" --add-comment "$(ffprobe -v error -show_entries format_tags=DESCRIPTION -of csv=p=0 "input.webm")" --remove-frame TXXX input.mp3

Update

In eyeD3 command line parameters colons should be properly escaped, otherwise they will be recognized as a delimiters:

#!/bin/bash
name="f.webm"
# Get the URL
video_url=$(ffprobe -v error -show_entries format_tags=PURL -of csv=p=0 "$name")
# Replace ":" with "\:"
video_url="${video_url//:/\:}"
# Write the URL
eyeD3 --user-url-frame ":$video_url" "${name%.*}.mp3"

Update 2

if description text is empty eyeD3 raises an exception and won't do any tasks that should be executed after this step. I looked into its source code - this behaviour is by design so and couldn't be turned off with some command line switches. It means that each operation should be performed separately after checking that corresponding variable is not empty:

if [[ ! -z "$video_url" ]]
then
  # Run eyeD3 only if variable is not empty because eyeD3 raises an exception and will not do any other tasks that might succeed
  eyeD3 --user-url-frame ":$video_url" "${name%.*}.mp3"
fi
if [[ ! -z "$video_dsc" ]]
then
  # Run eyeD3 only if variable is not empty because eyeD3 raises an exception and will not do any other tasks that might succeed
  eyeD3 --add-comment "$video_dsc" "${name%.*}.mp3"
fi
eyeD3 --remove-frame TXXX "${name%.*}.mp3"