Below is a plugin I am working on that once “scan” is pressed it SHOULD analyze the first file from an album to determine is bit rate and sample rate via ffprobe and add a custom metadata tag to the album stating what the results were for folder tagging.
This script works as intended when only 1 album is being processed in Picard but when I try to process multiple albums at once it does scan 1 file from each album folder as intended but it doesn’t accurately apply the format_tag to each album. If I add 10 albums it might add the correct tag to 3 or 4 albums but the rest don’t get the tag added even though the log generated by the plugin shows it properly scanning 1 file from each album folder and correctly giving the correct tag to be added.
Below is my plugin code, I would really appreciate and help or direction I can get. Thank you!
import os
import subprocess
import logging
from picard.metadata import register_album_metadata_processor
from threading import Lock
PLUGIN_NAME = "Log File Detector and FLAC Quality Tagger"
PLUGIN_AUTHOR = "Your Name"
PLUGIN_DESCRIPTION = (
"Adds folder tags ([CD-FLAC], [WEB-FLAC], [24-X-WEB-FLAC]) based on log files, bits_per_raw_sample, and sampling_rate."
)
PLUGIN_VERSION = "3.5"
PLUGIN_API_VERSIONS = ["2.0"]
# Thread-safe set for processed files and folders
processed_files = set()
processed_folders = set()
file_lock = Lock()
# Set up debug logging
log_file_path = r"G:\debug_log.txt"
logging.basicConfig(
filename=log_file_path,
level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s",
filemode="w",
)
logger = logging.getLogger(PLUGIN_NAME)
def get_audio_properties_with_ffprobe(file_path):
"""
Extracts bit depth (bits_per_raw_sample) and sample rate using ffprobe.
Returns (bit_depth, sample_rate) as integers, or (0, 0) if extraction fails.
"""
try:
command = [
"ffprobe",
"-v", "quiet",
"-select_streams", "a:0",
"-show_entries", "stream=sample_rate,bits_per_raw_sample",
"-of", "json",
file_path,
]
output = subprocess.check_output(command, text=True)
import json
data = json.loads(output)
stream = data.get("streams", [{}])[0]
sample_rate = int(stream.get("sample_rate", 0))
bit_depth = int(stream.get("bits_per_raw_sample", 0))
return bit_depth, sample_rate
except Exception as e:
logger.error(f"FFprobe error for {file_path}: {e}")
return 0, 0
def determine_folder_tag(album_metadata, metadata, release):
"""
Processes the album and assigns a folder tag based on file properties and log presence.
"""
global processed_folders, processed_files
folder_tag = ""
flac_file_found = False
# Get all files associated with the album
album_files = album_metadata.iterfiles()
if not album_files:
logger.debug("No files associated with the album.")
return
# Determine album path from the first file
album_path = os.path.dirname(next(iter(album_files)).filename)
with file_lock:
if album_path in processed_folders:
logger.debug(f"Skipping already processed folder: {album_path}")
return
else:
processed_folders.add(album_path)
logger.debug(f"Processing new folder: {album_path}")
# Check for a .log file in the album folder
try:
has_log_file = any(fname.lower().endswith(".log") for fname in os.listdir(album_path))
logger.debug(f"Log file detected: {has_log_file}")
except Exception as e:
logger.error(f"Error accessing folder {album_path}: {e}")
return
# Iterate over files to find the first FLAC file and analyze properties
for file in album_files:
if file.filename.lower().endswith(".flac"):
with file_lock:
if file.filename in processed_files:
logger.debug(f"Skipping already processed file: {file.filename}")
continue
processed_files.add(file.filename)
flac_file_found = True
logger.debug(f"FLAC file detected: {file.filename}")
# Extract metadata using FFprobe
bit_depth, sample_rate = get_audio_properties_with_ffprobe(file.filename)
logger.debug(
f"Track Details (FFprobe): Bit Depth = {bit_depth}, Sample Rate = {sample_rate}"
)
# Apply folder tag rules
if bit_depth == 24:
if sample_rate == 44100:
folder_tag = "[24-44.1-WEB-FLAC]"
elif sample_rate == 48000:
folder_tag = "[24-48-WEB-FLAC]"
elif sample_rate == 88200:
folder_tag = "[24-88.2-WEB-FLAC]"
elif sample_rate == 96000:
folder_tag = "[24-96-WEB-FLAC]"
elif sample_rate == 176400:
folder_tag = "[24-176-WEB-FLAC]"
elif sample_rate == 192000:
folder_tag = "[24-192-WEB-FLAC]"
elif bit_depth == 16 and sample_rate == 44100:
if has_log_file:
folder_tag = "[CD-FLAC]"
else:
folder_tag = "[WEB-FLAC]"
# Stop after processing the first FLAC file
break
# Assign the folder tag to metadata if a FLAC file was found
if flac_file_found:
metadata["folder_tag"] = folder_tag
logger.debug(f"Folder Tag Assigned: {folder_tag}")
else:
logger.debug("No FLAC files found in the album.")
# Register the plugin to process album metadata
register_album_metadata_processor(determine_folder_tag)