import logging from datetime import timedelta from math import isclose from subprocess import CalledProcessError from typing import Any, Dict from ._ffmpeg import compute_silences, probe_duration logger = logging.getLogger(__name__) def analyze_duration(filepath: str, metadata: Dict[str, Any]) -> Dict[str, Any]: """ Extracts the file duration using ffmpeg. """ try: duration = probe_duration(filepath) if "length_seconds" in metadata and not isclose( metadata["length_seconds"], duration, abs_tol=0.1, ): logger.warning( f"existing duration {metadata['length_seconds']} differs " f"from the probed duration {duration}." ) metadata["length_seconds"] = duration metadata["length"] = str(timedelta(seconds=duration)) metadata["cuein"] = 0.0 metadata["cueout"] = duration except (CalledProcessError, OSError): pass return metadata def analyze_cuepoint(filepath: str, metadata: Dict[str, Any]) -> Dict[str, Any]: """ Extracts the cuein and cueout times using ffmpeg. This step must run after the 'analyze_duration' step. """ # Duration has been computed in the 'analyze_duration' step duration = metadata["length_seconds"] try: silences = compute_silences(filepath) if len(silences) > 2: # Only keep first and last silence silences = silences[:: len(silences) - 1] for silence in silences: # Sanity check if silence[0] >= silence[1]: raise ValueError( f"silence starts ({silence[0]}) after ending ({silence[1]})" ) # Is this really the first silence ? if isclose( 0.0, max(0.0, silence[0]), # Clamp negative value abs_tol=0.1, ): metadata["cuein"] = max(0.0, silence[1]) # Is this really the last silence ? elif isclose( min(silence[1], duration), # Clamp infinity value duration, abs_tol=0.1, ): metadata["cueout"] = min(silence[0], duration) metadata["cuein"] = format(metadata["cuein"], "f") metadata["cueout"] = format(metadata["cueout"], "f") except (CalledProcessError, OSError): pass return metadata