108 lines
3.4 KiB
Python
108 lines
3.4 KiB
Python
import os
|
|
import time
|
|
import tempfile
|
|
import streamlit as st
|
|
from config import PYGAME_AVAILABLE, MOVIEPY_AVAILABLE
|
|
|
|
if PYGAME_AVAILABLE:
|
|
import pygame
|
|
|
|
if MOVIEPY_AVAILABLE:
|
|
from moviepy import VideoFileClip
|
|
|
|
class AudioPlayer:
|
|
"""A class to handle audio extraction and playback for the video."""
|
|
|
|
def __init__(self):
|
|
self.is_playing = False
|
|
self.audio_file = None
|
|
self.start_time = None
|
|
self.pygame_initialized = False
|
|
|
|
if PYGAME_AVAILABLE:
|
|
try:
|
|
# Initialize pygame mixer with a specific frequency to avoid common issues
|
|
pygame.mixer.pre_init(frequency=44100, size=-16, channels=2, buffer=512)
|
|
pygame.mixer.init()
|
|
self.pygame_initialized = True
|
|
except Exception as e:
|
|
st.warning(f"Audio mixer initialization failed: {e}")
|
|
|
|
def extract_audio_from_video(self, video_path):
|
|
"""Extracts audio from a video file using MoviePy."""
|
|
if not MOVIEPY_AVAILABLE or not self.pygame_initialized:
|
|
return None
|
|
|
|
try:
|
|
temp_audio = tempfile.mktemp(suffix='.wav')
|
|
video_clip = VideoFileClip(video_path)
|
|
if video_clip.audio is not None:
|
|
video_clip.audio.write_audiofile(temp_audio, logger=None)
|
|
video_clip.close()
|
|
return temp_audio
|
|
else:
|
|
video_clip.close()
|
|
return None
|
|
except Exception as e:
|
|
st.warning(f"Could not extract audio: {e}")
|
|
return None
|
|
|
|
def load_audio(self, video_path):
|
|
"""Loads an audio file for playback."""
|
|
if not self.pygame_initialized:
|
|
return False
|
|
|
|
try:
|
|
audio_file = self.extract_audio_from_video(video_path)
|
|
if audio_file and os.path.exists(audio_file):
|
|
self.audio_file = audio_file
|
|
return True
|
|
return False
|
|
except Exception as e:
|
|
st.error(f"Failed to load audio: {e}")
|
|
return False
|
|
|
|
def play(self):
|
|
"""Plays the loaded audio file."""
|
|
if not self.pygame_initialized or not self.audio_file or self.is_playing:
|
|
return False
|
|
try:
|
|
pygame.mixer.music.load(self.audio_file)
|
|
pygame.mixer.music.play()
|
|
self.is_playing = True
|
|
self.start_time = time.time()
|
|
return True
|
|
except Exception as e:
|
|
st.warning(f"Audio playback failed: {e}")
|
|
return False
|
|
|
|
def stop(self):
|
|
"""Stops the audio playback."""
|
|
if self.pygame_initialized and self.is_playing:
|
|
try:
|
|
pygame.mixer.music.stop()
|
|
self.is_playing = False
|
|
return True
|
|
except Exception as e:
|
|
return False
|
|
return False
|
|
|
|
def restart(self):
|
|
"""Restarts the audio from the beginning."""
|
|
if self.pygame_initialized and self.audio_file:
|
|
self.stop()
|
|
# Small delay to ensure proper stopping
|
|
time.sleep(0.1)
|
|
return self.play()
|
|
return False
|
|
|
|
def cleanup(self):
|
|
"""Cleans up audio resources."""
|
|
self.stop()
|
|
if self.audio_file and os.path.exists(self.audio_file):
|
|
try:
|
|
os.unlink(self.audio_file)
|
|
self.audio_file = None
|
|
except Exception:
|
|
pass
|