What does beets do with already existing .lrc files?

I’ll keep updating here as I get closer to what I’m looking for. (Script needs ffmpeg and ffprobe, can easily be adapted for non-bash shells, will do later). I have beets setup in a virtual environment, so that can be removed if you have it install on your system and added to path.

I also have Plex Media Server set up (which unfortunately doesn’t support ID3 tags very well)… So for lyrics I’m dependant on the .lrc files.

Quick overview of what this script does:

  1. Scans media files based on the list of extensions
  2. Reads lyrics in the file.
  3. If, Then, Else
  • If it’s synced, leave the file alone, and delete .lrc if it exists (my import and library folders are separate, which is why the 2nd part is done)
  • Otherwise if it’s unsynced, look for synced lyrics (.lrc file) and embed
  • If it’s unsynced and no .lrc file exists, strip the lyrics from the file so beets can autotag it with synced lyrics. Or leave it alone if it’s blank.
  1. Beet Update/Import/Convert
  2. Extracts the lyrics (.lrc and .txt) from all media files in the library (and exports a list of songs with unsynced lyrics to the library’s parent folder) for Plex Media Server to read

ROOT_DIR is just where the script is (the /home/$USER directory in my case)

#!/bin/bash
shopt -s globstar nocaseglob

# Get the directory of the script
ROOT_DIR="$(dirname "$(realpath "$0")")"
# State Import/Library folders
IMPORT_DIR="/home/${USER}/Downloads/Music"
LIBRARY_DIR="/home/${USER}/Music/Library"

# List of extensions of media files.
extensions=("flac" "m4a" "mp3")

### Embed Synced Lyrics in music to be imported
# Go to Import Directory
cd "$IMPORT_DIR"
find . -type f -name *.txt -delete

for ext in ${extensions[@]}; do
	if [[ "$ext" == "flac" ]]; then
		tags="LYRICS"
	else
		tags="lyrics"
	fi

	for file in **/*."$ext"; do
		# Get lyrics from metadata
		lyrics=$(ffprobe -loglevel error -show_entries format_tags="$tags" -of default=noprint_wrappers=1:nokey=1 "$file")
		# If not empty, check if it's synced and try to embed if not.
		if ! [ -z "$lyrics" ]; then
			# If synced, leave untouched
			if echo "$lyrics" | grep -qE '^\[[0-9]{2}:[0-9]{2}.[0-9]{2}\]'; then
				echo "Synced lyrics already embedded in '$file'."
				if [ -e "${file%.*}.lrc" ]; then rm "${file%.*}.lrc"; fi
			# If not synced, look for .lrc file and embed
			elif [ -e "${file%.*}.lrc" ]; then
				lyrics="${file%.*}.lrc"
				temp_file="${file%.*}_temp.${file##*.}"
				ffmpeg -i "$file" -map 0 -c copy -metadata "$tags"="$(cat "$lyrics")" "$temp_file"
				mv "$temp_file" "$file"
				rm "$lyrics"
			# Otherwise, strip for autotagging in beets
			else
				echo "Stripping lyrics from '$file' for autotagging."
				temp_file="${file%.*}_temp.${file##*.}"
				ffmpeg -i "$file" -map 0 -c copy -metadata "$tags"="" "$temp_file"
				mv "$temp_file" "$file"
			fi
		# Embed synced lyrics if available
		elif [ -e "${file%.*}.lrc" ]; then
			lyrics="${file%.*}.lrc"
			temp_file="${file%.*}_temp.${file##*.}"
			ffmpeg -i "$file" -map 0 -c copy -metadata "$tags"="$(cat "$lyrics")" "$temp_file"
			mv "$temp_file" "$file"
			rm "$lyrics"
		# Otherwise, just state it's empty
		else
			echo "'$file' has no lyrics"
		fi
	done
done

### Import all Music to Library
source "$ROOT_DIR/beets/bin/activate"
beet update
beet import "$IMPORT_DIR"
beet convert -y
deactivate

### Export (hopefully now Synced) Lyrics to .lrc file for Plex Media Server
cd "$LIBRARY_DIR"

for ext in ${extensions[@]}; do
	if [[ "$ext" == "flac" ]]; then
		tags="LYRICS"
	else
		tags="lyrics"
	fi
	
	for file in **/*."$ext"; do
		# Check if any exported lyrics exists, delete unsynced if both exists
		if [ -e "${file%.*}.lrc" ] && [ -e "${file%.*}.txt" ]; then
			rm "${file%.*}.txt"
		# If only unsynced exists
		elif [ -e "${file%.*}.txt" ]; then
			# Read Lyrics from file
			lyrics=$(ffprobe -loglevel error -show_entries format_tags="$tags" -of default=noprint_wrappers=1:nokey=1 "$file")		
			# Ensure lyrics aren't empty
			if ! [ -z "$lyrics" ]; then
				# If synced, delete unsynced and save synced
				if echo "$lyrics" | grep -qE '^\[[0-9]{2}:[0-9]{2}.[0-9]{2}\]'; then
					echo "Synced lyrices for '$file' found, removing unsynced."
					rm "${file%.*}.txt"
					echo "$lyrics" > "${file%.*}.lrc"
				else
					echo "No synced lyrics found, leaving files intact."
                    echo "$file" >> "unsynced.txt"
				fi
			fi
		# If no lyrics exists.
		elif [ ! -e "${file%.*}.txt" ] && [ ! -e "${file%.*}.lrc" ]; then
			# Read Lyrics from file
			lyrics=$(ffprobe -loglevel error -show_entries format_tags="$tags" -of default=noprint_wrappers=1:nokey=1 "$file")		
			# Ensure lyrics aren't empty
			if ! [ -z "$lyrics" ]; then
				# If synced, delete unsynced and save synced
				if echo "$lyrics" | grep -qE '^\[[0-9]{2}:[0-9]{2}.[0-9]{2}\]'; then
					echo "Exporting synced lyrics for '$file'."
					echo "$lyrics" > "${file%.*}.lrc"
				else
					echo "Exporting unsynced lyrics for '$file'."
					echo "$lyrics" > "${file%.*}.txt"
					echo "$file" >> "unsynced.txt"
				fi
			fi
		else
			echo "Lyrics already exists for '$file'"
		fi
	done
done