diff --git a/app/services/sound_normalizer_service.py b/app/services/sound_normalizer_service.py index 00e9588..846036b 100644 --- a/app/services/sound_normalizer_service.py +++ b/app/services/sound_normalizer_service.py @@ -7,7 +7,6 @@ import re from pathlib import Path import ffmpeg -from pydub import AudioSegment from app.database import db from app.models.sound import Sound @@ -632,9 +631,17 @@ class SoundNormalizerService: # Calculate file hash file_hash = SoundNormalizerService._calculate_file_hash(file_path) - # Get duration using pydub - audio = AudioSegment.from_wav(file_path) - duration = len(audio) # Duration in milliseconds + # Get duration using ffmpeg + probe = ffmpeg.probe(file_path) + audio_stream = next( + (s for s in probe['streams'] if s['codec_type'] == 'audio'), + None + ) + + if audio_stream and 'duration' in audio_stream: + duration = int(float(audio_stream['duration']) * 1000) # Convert to milliseconds + else: + duration = 0 return { "duration": duration, diff --git a/app/services/sound_scanner_service.py b/app/services/sound_scanner_service.py index 025d286..d7da5e9 100644 --- a/app/services/sound_scanner_service.py +++ b/app/services/sound_scanner_service.py @@ -4,8 +4,7 @@ import hashlib import logging from pathlib import Path -from pydub import AudioSegment -from pydub.utils import mediainfo +import ffmpeg from app.database import db from app.models.sound import Sound @@ -281,32 +280,31 @@ class SoundScannerService: @staticmethod def _extract_audio_metadata(file_path: str) -> dict: - """Extract metadata from audio file using pydub and mediainfo.""" + """Extract metadata from audio file using ffmpeg-python.""" try: # Get file size file_size = Path(file_path).stat().st_size - # Load audio file with pydub for basic info - audio = AudioSegment.from_file(file_path) + # Use ffmpeg to probe audio metadata + probe = ffmpeg.probe(file_path) + audio_stream = next( + (s for s in probe['streams'] if s['codec_type'] == 'audio'), + None + ) + + if not audio_stream: + raise ValueError("No audio stream found in file") - # Extract basic metadata from AudioSegment - duration = len(audio) - channels = audio.channels - sample_rate = audio.frame_rate - - # Use mediainfo for more accurate bitrate information - bitrate = None - try: - info = mediainfo(file_path) - if info and "bit_rate" in info: - bitrate = int(info["bit_rate"]) - elif info and "bitrate" in info: - bitrate = int(info["bitrate"]) - except (ValueError, KeyError, TypeError): - # Fallback to calculated bitrate if mediainfo fails - if duration > 0: - file_size_bits = file_size * 8 - bitrate = int(file_size_bits / duration / 1000) + # Extract metadata from ffmpeg probe + duration = int(float(audio_stream.get('duration', 0)) * 1000) # Convert to milliseconds + channels = int(audio_stream.get('channels', 0)) + sample_rate = int(audio_stream.get('sample_rate', 0)) + bitrate = int(audio_stream.get('bit_rate', 0)) if audio_stream.get('bit_rate') else None + + # Fallback bitrate calculation if not available + if not bitrate and duration > 0: + file_size_bits = file_size * 8 + bitrate = int(file_size_bits / (duration / 1000)) return { "duration": duration, diff --git a/pyproject.toml b/pyproject.toml index 5f52b2f..15b842d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,6 @@ dependencies = [ "flask-migrate==4.1.0", "flask-socketio==5.5.1", "flask-sqlalchemy==3.1.1", - "pydub==0.25.1", "python-dotenv==1.1.1", "python-vlc>=3.0.21203", "requests==2.32.4", diff --git a/uv.lock b/uv.lock index 5544af3..277ee6a 100644 --- a/uv.lock +++ b/uv.lock @@ -505,15 +505,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, ] -[[package]] -name = "pydub" -version = "0.25.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/9a/e6bca0eed82db26562c73b5076539a4a08d3cffd19c3cc5913a3e61145fd/pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f", size = 38326 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327 }, -] - [[package]] name = "pygments" version = "2.19.2" @@ -645,7 +636,6 @@ dependencies = [ { name = "flask-migrate" }, { name = "flask-socketio" }, { name = "flask-sqlalchemy" }, - { name = "pydub" }, { name = "python-dotenv" }, { name = "python-vlc" }, { name = "requests" }, @@ -671,7 +661,6 @@ requires-dist = [ { name = "flask-migrate", specifier = "==4.1.0" }, { name = "flask-socketio", specifier = "==5.5.1" }, { name = "flask-sqlalchemy", specifier = "==3.1.1" }, - { name = "pydub", specifier = "==0.25.1" }, { name = "python-dotenv", specifier = "==1.1.1" }, { name = "python-vlc", specifier = ">=3.0.21203" }, { name = "requests", specifier = "==2.32.4" },