Can’t get plugin to scan different file when multiple albums are being professes

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)

The debut log for the script shows all albums were properly detected and had the correct format applied to them, but only 2 had the actual tag applied to the album metadata so it’s kind of working but something is getting lost even though the script debug log states and shows it did identify everything correctly.

  1. The very last line of this plugin shows you have hooked it in to run after the release metadata has been downloaded from MusicBrainz and applied to the album. It does NOT run when you click Scan.

  2. I am unclear why you are using a self-generated logger rather than the Picard built-in logger.

  3. I can’t immediately see why it processes the same file for each album.

I am just using a self generated log to just verify if it did in face detect 1 sing from each album folder correctly instead of going through all the debug code if Picard.

When i group and click Scan is when the plugin does run as the ffprobe cmd line prompt pops up briefly when each album is being identified and matched.